hibernate.zzh

1、hibernate是什么

框架是什么:

1、框架是用来提高开发效率的
2、封装好了一些功能,我们需要使用这些功能时,调用即可,不需要再手动实现
3、框架可以理解为一个半成品得项目,只要懂得如何驾驭这些功能即可

2、hibernate框架是什么,dao层框架

3、hibernate的好处

操作数据库的时候,可以以面向对象的方式来完成,不需要书写sql语句(hibernate十款orm框架)

ORM:利用描述对象和数据库表之间映射的元数据,自动把java应用程序中的对象,持久化到关系型数据库的表中。

4、orm分四级

1、dbutils属于1级
2、mybatis数据2级
4、hibernate数据4级:完全面向对象操作数据库

3、hibernate框架的构建

导包——创建数据库,准备表——书写orm元数据(对象与表的映射配置文件)——书写主配置文件——书写代码测试导包:

创建表:

书写orm元数据:①导入约束②实体③orm元数据

①导入约束


②实体③orm元数据


配置ORM元数据

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- 配置表与实体对象的关系 -->
    <!-- package属性:填写一个包名,在元素内部凡是需要书写完整类名的属性,可以直接输入类名 -->
<hibernate-mapping package="hibernate_day01.domain">
    <!--
     class元素:配置实体与表的对应关系
        name:完整类名
        table:数据库表名 
     -->
    <class name="Customer" table="cst_customer">
        <!-- 
            id元素:配置主键映射的属性
            name:填写主键对应属性名
            column:填下表中的主键列名
         -->
        <id name="cust_id" column="cust_id">
            <!-- generator:主键生成策略 -->
            <generator class="native"></generator>
        </id>
        <!-- property元素:除id以外的普通属性映射
            name:填写属性名
            column:填写列名,默认是name的属性值
            not-null:配置该属性是否不能为空,默认值为false
            length:配置数据库中列的长度,默认值:使用数据库类型的最大长度
         -->
        <property name="cust_name" column="cust_name"></property>
        <property name="cust_source" column="cust_source"></property>
        <property name="cust_industry" column="cust_industry"></property>
        <property name="cust_level" column="cust_level"></property>
        <property name="cust_phone" column="cust_phone"></property>
        <property name="cust_mobile" column="cust_mobile"></property>
    </class>
</hibernate-mapping>

hibernate主配置文件(位于src下)

必选属性配置(5个):
1、数据库驱动
2、数据库url
3、数据库连接用户名
4、数据库连接密码
5、数据库方言:不同的数据库,比如Oracle,MSSQL,MySQL,它们的SQL会有少量的差别,内置函数也会有点不同,比如limit,在Oracle里面就不能用,
可选属性配置:
元数据引入配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- #hibernate.dialect org.hibernate.dialect.MySQLDialect
        #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
        #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
        #hibernate.connection.driver_class com.mysql.jdbc.Driver
        #hibernate.connection.url jdbc:mysql:///test
        #hibernate.connection.username gavin
        #hibernate.connection.password -->
        
        <!-- 数据库驱动 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 数据库名 -->
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate_01</property>
        <!-- 数据库连接用户名 -->
        <property name="hibernate.connection.username">root</property>
        <!-- 数据库连接密码 -->
        <property name="hibernate.connection.password">123</property>
        <!-- 数据库方言 
            不同的数据库中,sql语法略有区别,指定方言可以让hibernate框架在生成sql语句时,针对数据库的方言生成
            sql99标准:DDL 定义语言 库表的增删改查
                     DCL 控制语言 事务权限
                     DML 操纵语言 增删改查
            注意:mysql选择方言时,选择最短的数据库方言            
        -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        
        
        <!-- #hibernate.show_sql true
            #hibernate.format_sql true -->
        <!-- 将hibernate生成的sql语句打印到控制台 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 将hibernate生成的sql语句格式化(语法缩进) -->
        <property name="hibernate.format_sql">true</property>
        <!-- auto schema export 自动导出表结构 自动建表 -->
        <!--    
        #hibernate.hbm2ddl.auto create-drop 自动建表 每次框架运行结束都会删除所有表
        #hibernate.hbm2ddl.auto create 自动建表 每次框架运行都会创建新的表,以前表将会被覆盖,数据会丢失
        #hibernate.hbm2ddl.auto update(推荐使用) 自动生成表,如果已存在不会再生成,如果表有改动,则执行改动
        #hibernate.hbm2ddl.auto validate 校验,不自动生成,每次启动会校验数据库表是否正确。校验失败-->
        <property name="hibernate.hbm2ddl.auto"></property>
        <!-- 引入orm元数据
            路径书写:填写src下的路径
         -->
        <mapping resource="hibernate_day01/domain/Customer.hbm.xml"/>
        <!-- 指定hibernate操作数据库时的隔离级别
            #hibernate.connection.isolation 1|2|4|8
            0001 1 读未提交
            0010 2 读已提交
            0100 4 可重复读
            1000 8 串行化
         -->
         <property name="hibernate.connection.isolation">4</property>
    </session-factory>
</hibernate-configuration>

api详解

package hibernate_day01.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import hibernate_day01.domain.Customer;
//学习Configuration对象
//configuration功能:配置加载类,用于加载主配置,orm元数据加载
public class Demo {
    @Test
    public void fun1() {
        //调用空参构造
        Configuration conf = new Configuration().configure();
        //读取指定主配置文件   空参加载方法,加载src下的“hibernate.cfg.xml”文件
        //根据配置信息,创建sessionFactory对象,这个对象的功能是用于创建操作数据库核心对象session对象的工厂
        //功能只有创建session对象
        //注意:1、sessionFactory负责保存和使用所有配置信息,消耗内存资源非常大
        //    2、sessionFactory属于线程安全的对象设计
        //结论:保证在web项目中,只创建一个sessionFactory
        SessionFactory sf = conf.buildSessionFactory();
        //获得session 此处的session表达hibernate框架与数据库之间的连接(会话)
        //JDBC年代的connection对象,还可以完成对数据库中数据的增删改查
        //session是hibernate操作数据库的核心对象
        //打开一个新的session对象
        Session session = sf.openSession();
        //session获得操作事务的Transaction对象
        //开启事务并获得操作事务的tx对象
        Transaction tx = session.beginTransaction();
        Customer c = new Customer();
        c.setCust_name("朱展鸿");
        session.save(c);
        
        tx.commit();
        session.close();
        sf.close();
    }
    
    //根据id查询
    @Test
    public void fun2() {
        Configuration conf = new Configuration().configure();
        
        SessionFactory sf = conf.buildSessionFactory();
        
        Session session = sf.openSession();
    
        Transaction tx = session.beginTransaction();

        Customer customer = session.get(Customer.class, 3l);
        System.out.println(customer);
        
        tx.commit();
        session.close();
        sf.close();
    }
    
    //session的修改
    @Test
    public void fun3() {
        Configuration conf = new Configuration().configure();
        
        SessionFactory sf = conf.buildSessionFactory();
        
        Session session = sf.openSession();
    
        Transaction tx = session.beginTransaction();

        Customer customer = session.get(Customer.class, 3l);
        customer.setCust_name("zzh");
        session.update(customer);
        
        tx.commit();
        session.close();
        sf.close();
    }
    
    //对象导航查询
    @Test
    public void testSelectObject(){
        Session session = null;
        Transaction transaction = null;
        try {
            //1.使用SessionFactory创建Session对象
            //理解:类似于jdbc的连接数据库
            session = HibernateUtils.getSessionObject();
            //2.开启事务
            transaction = session.beginTransaction();
            //3.写具体的crud操作
            //查询cid=3的客户,在查询他的所有联系人
            //01.查询cid=3的客户
            Customer customer = session.get(Customer.class, 3l);
            //02.再查询cid=3的客户的所有联系人
            //通过客户的联系人属性获取其所有的联系人
            Set<LinkMan> linkMans = customer.getSetLinkMan();
            for (LinkMan linkMan : linkMans) {
                System.out.println(linkMan);
            }
            //4.提交事务
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //5.回滚事务
            transaction.rollback();
        } finally {
            //6.关闭资源     在使用了与本地线程绑定的session对象之后,就不需要手动关闭session了
            session.close();
        }
    }

    
    //删除操作
    @Test
    public void fun4() {
        Configuration conf = new Configuration().configure();
        
        SessionFactory sf = conf.buildSessionFactory();
        
        Session session = sf.openSession();
    
        Transaction tx = session.beginTransaction();

        Customer customer = session.get(Customer.class, 3l);
        session.delete(customer);
        
        tx.commit();
        session.close();
        sf.close();
    }
}

orm配置文件和主配置文件




02hibernate中的实体规则

1、实体创建的注意事项:
1、持久化类提供无参数构造
2、成员变量私有,提供又get/set方法访问,需要提供属性,属性指的是get/set方法
3、持久化类中的属性,应尽量使用包装类型
4、持久化类需要提供oid,与数据库中的主键列对应,实体中必须有一个与主键对应的属性
5、不能用final修饰class(hibernate使用cglib代理生成代理对象,代理对象是继承被代理对象,如果被final修饰,将无法生成),当用final修饰一个类时,表明这个类不能被继承
2、主键类型:
1、自然主键——表的业务列中,有某业务列符合必须有且不重复的特征时,该列可以作为主键使用,例如人力管理系统中的身份证号
2、代理主键——表的业务列中,有某业务列不需符合必须有且不重复的特征时,创建一个没有业务意义的列作为主键,例如user表和product表
<!-- 
            id元素:配置主键映射的属性
            name:填写主键对应属性名
            column:填下表中的主键列名
         -->
        <id name="cust_id" column="cust_id">
            <!-- generator:主键生成策略 
                每条记录录入时,主键的生成规则
                identity:主键自增,由数据库来维护主键值,录入时不需要指定主键
                increment:主键自增,由hibernate来维护,每次插入前会先查询表中id最大值,+1作为新主键值
                hilo:高低位算法,主键自增,由hibernate维护
                sequence:Oracle中的主键生成策略
                native:hilo+sequence+identity自动三选一策略
                uuid:产生随机字符串作为主键,主键类型必须为字符串类型
                assigned:自然主键生成策略,hibernate不会管理主键值,由开发人员自己录入
            -->
            <generator class="native"></generator>
        </id>
hibernate中的对象状态:
1、瞬时状态:没有id,没有在session缓存中
2、持久化状态(指在缓存对象中):有id,在session缓存中
3、游离|托管状态:有id,没有在session缓存中
public class Demo {
    @Test
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        Customer c = new Customer();//瞬时状态,没有id,没有与session关联
        c.setCust_name("狗东");//瞬时状态
        session.save(c);//持久化状态,有id,有关联
        
        tx.commit();
        session.close();//游离状态,有id,没关联
    }
}
三种状态的转换:

hibernate进阶-一级缓存:
缓存:提高效率,hibernate中的一级缓存也是为了提高操作数据库的效率
一级缓存:为了提高效率,session对象中有一个可以存放对象的集合
查询时:第一次查询时,会将对象放入缓存,再次查询时,会返回缓存中的对象,不再查询数据库
修改时:会使用快照对比修改前和修改后对象的属性区别,只执行一次修改

减少不必要的操作:

hibernate中的事务:
事务:a——原子性  
           c——一致性
           i——隔离性
           d——持久性
在项目中如何管理事务:业务开始之前打开业务,业务执行之后提交事务,执行过程中出现异常,回滚事务

隔离级别:
1 读未提交
2 读已提交
4 可重复读
8 串行化

在dao层操作数据库需要用到session对象,而在service层控制事务时也需要使用session,我们要确保dao层和service层的session是同一个session,避免发生线程错误
在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了,只需要调用sf.getCurrentSession()方法即可获得与当前线程绑定的session对象。
注意1:调用getCurrentSession方法必须配合主配置的一段配置
<!-- 指定session与当前线程绑定 -->
         <property name="hibernate.current_session_context_class">thread</property>
注意2:通过getCurrentSession方法获得的session对象,当事务提交时,session会自动关闭,不要手动调用close方法
hibernate中的批量查询(概述):
1、HQL查询-hibernate Query Language(可以多表查询,不复杂时使用):hibernate的独家查询语言,是面向对象的查询语言
public class Demo {
    //条件查询
    @Test
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //1、书写hql语句
        String hql = " from Customer ";//查询所有Customer对象
        //2、根绝hql创建查询对象
        Query query = session.createQuery(hql);
        //3、根据查询对象获得查询结果
        List<Customer> list = query.list();
        System.out.println(list);
        
        tx.commit();
        session.close();
    }
    
    //条件查询
    //HQL语句中,不可能出现任何数据库相关的信息
    @Test
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //1、书写hql语句
        String hql = " from Customer where cust_id = 1 ";//cust_id是属性名,不是列名
        //2、根绝hql创建查询对象
        Query query = session.createQuery(hql);
        //3、根据查询对象获得查询结果
        Customer c = (Customer) query.uniqueResult();
        System.out.println(c);
        
        tx.commit();
        session.close();
    }
    
    //问号占位符
    @Test
    public void fun3() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //1、书写hql语句
        String hql = " from Customer where cust_id = ? ";//cust_id是属性名,不是列名
        //2、根绝hql创建查询对象
        Query query = session.createQuery(hql);
        //设置参数
        query.setParameter(0, 1l);
        //3、根据查询对象获得查询结果
        Customer c = (Customer) query.uniqueResult();
        System.out.println(c);
        
        tx.commit();
        session.close();
    }   
    
    //命名占位符
    @Test
    public void fun4() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //1、书写hql语句
        String hql = " from Customer where cust_id = :cust_id ";//cust_id是属性名,不是列名
        //2、根绝hql创建查询对象
        Query query = session.createQuery(hql);
        //设置参数
        query.setParameter("cust_id", 1l);
        //3、根据查询对象获得查询结果
        Customer c = (Customer) query.uniqueResult();
        System.out.println(c);
        
        tx.commit();
        session.close();
    }   
    
    //分页
    @Test
    public void fun5() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //1、书写hql语句
        String hql = " from Customer ";//cust_id是属性名,不是列名
        //2、根绝hql创建查询对象
        Query query = session.createQuery(hql);
        //设置分页信息
        query.setFirstResult(1);
        query.setMaxResults(2);//一次查询多少条
        //3、根据查询对象获得查询结果
        List<Customer> list =  query.list();
        System.out.println(list);
        
        tx.commit();
        session.close();
    }   
}
2、Criteria查询(单表查询):hibernate自创的无语句面向对象查询
//criteria查询
    @Test
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Criteria criteria = session.createCriteria(Customer.class);
        List<Customer> list = criteria.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }
    
    //条件查询
    // >                gt      
    // >=               ge
    // <                lt
    // <=               le
    // ==               eq
    // !=               ne
    // in               in
    // between and      between
    // like             like
    // is not null      isnotnull
    // is null          isnull
    // or               or
    // and              and
    @Test
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Criteria criteria = session.createCriteria(Customer.class);
        //添加查询参数 查询cust_id为1的customer对象
        criteria.add(Restrictions.eq("cust_id", 1l));
        //通过criteria对象获得查询结果
        Customer c = (Customer) criteria.uniqueResult();
        tx.commit();
        session.close();
    }
    
    //分页查询
    @Test
    public void fun3() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.setFirstResult(0);
        criteria.setMaxResults(1);
        List<Customer> list = criteria.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }
    
    
    //查询总记录数
    @Test
    public void fun4() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Criteria criteria = session.createCriteria(Customer.class);
        //设置查询的聚合函数 总行数
        criteria.setProjection(Projections.rowCount());
        //执行查询
        Long count = (Long) criteria.uniqueResult();
        System.out.println(count);
        tx.commit();
        session.close();
    }
3、原生SQL查询(复杂的业务查询)
//原声mysql查询
    @Test
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //书写sql语句
        String sql = "select * from cst_customer";
        //创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);
        //指定将结果封装到哪个对象中
        query.addEntity(Customer.class);
        //调用方法查询结果
        /*List<Object[]> list = query.list();
        for(Object[] obj:list) {
            System.out.println(Arrays.toString(obj));
        }*/
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }
    
    
    //条件查询
    @Test
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //书写sql语句
        String sql = "select * from cst_customer where cust_id = ?";
        //创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);
        query.setParameter(0, 1l);
        //指定将结果封装到哪个对象中
        query.addEntity(Customer.class);
        //调用方法查询结果
        /*List<Object[]> list = query.list();
        for(Object[] obj:list) {
            System.out.println(Arrays.toString(obj));
        }*/
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }
    
    //分页查询
    @Test
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //书写sql语句
        String sql = "select * from cst_customer limit ?,?";
        //创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);
        query.setParameter(0, 0);
        query.setParameter(1, 1);
        //指定将结果封装到哪个对象中
        query.addEntity(Customer.class);
        //调用方法查询结果
        /*List<Object[]> list = query.list();
        for(Object[] obj:list) {
            System.out.println(Arrays.toString(obj));
        }*/
        List<Customer> list = query.list();
        System.out.println(list);
        tx.commit();
        session.close();
    }   

多表查询

多对一|一对多:
O    对象         一的一方使用集合,多的一方直接引用一的一方
R    关系型数据库        多的一方使用外键引用一的一方主键 
M    映射文件   
 一: <set name="">
       <key column="" />
       <one-to-many class="" />
      </set>
     多: <many-to-one name="" column="" class="" />
 操作: 操作管理级别属性. 
  cascade: 级联操作 
   减少我们书写的操作代码.
   none(默认值) 不级联
   save-update: 级联保存
   delete: 级联删除
   all: 级联保存+级联删除
  结论: 可以使用save-update.不推荐使用delete. 也可以不用cascade.
  inverse: 反转关系维护
   属于性能优化.关系的两端如果都书写了关系.那么两方都会发送维护关系的语句.
   这样,语句就发生重复.我们可以使用inverse使一的一方放弃维护关系.
   true 放弃
   false(默认值) 维护
  结论: 在一对多中,一的一方可以放弃维护关系.


1、表中的表达
2、实体中的表达:
3、一对多关系在xml里的配置
        <!-- 集合,一对多关系,在配置文件中的配置 -->
        <!-- 
            name属性:集合属性名
            column属性:外键列名
            class属性:与我关联的对象的完整包名
         -->
         <!-- 
            级联操作:cascade
            save-update:级联保存更新
            dalete:级联删除(不建议使用,误操作后果严重)
            all :save-update和delete同时配
            级联操作:简化操作,简化代码
         -->
        <!-- inverse属性
            true:customer不维护关系
            false(默认值):customer维护关系
            inverse属性:性能优化,提高关系维护的性能
            原则:无论怎么放弃,总有一方必须要维护关系
            一对多关系中:一的一方放弃,也只能是一的一方放弃,多的一方不能放弃
         -->
        <set name="LinkMen" cascade="sava-update" inverse="true">
            <key column="lkm_cust_id"></key>
            <one-to-many class="LinkMan" />
        </set>
        <!-- 集合,多对一,在配置文件中的配置 -->
        <!-- 
            name属性:集合属性名
            column属性:外键列名
            class属性:与我关联的对象的完整包名
         -->
        <!-- 多的一方:不能放弃维护关系,外键字段在多的一方 -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer"></many-to-one>
4、相关操作:
public class Demo {
    @Test
    public void fun1() {
        //1、获得session
        Session session = HibernateUtils.openSession();
        //2、开启事务
        Transaction tx = session.beginTransaction();
        //3、操作
        Customer c = new Customer();
        c.setCust_name("狗东");
        
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("刘强东");
        
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("奶茶妹");
        
        //表示一对多,客户下有多个联系人
        c.getLinkMen().add(lm1);
        c.getLinkMen().add(lm2);
        
        //表示多对一,多个联系人对应一个客户,如果客户放弃维护关系,则以下两行代码可省略
        lm1.setCustomer(c);
        lm2.setCustomer(c);
        
        //将对象转化为持久化状态
        //session.save(lm1);
        //session.save(lm2);
        session.save(c);
        
        //4、提交事务
        tx.commit();
        //5、关闭资源
        session.close();
    }
    
    //添加联系人
    @Test
    public void fun2() {
        //1、获得session
        Session session = HibernateUtils.openSession();
        //2、开启事务
        Transaction tx = session.beginTransaction();
        //3、操作
        //获得需要操作的客户对象
        Customer c = session.get(Customer.class, 4l);
        //创建新的联系人
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("马云");
        //将新的联系人添加到客户当中
        c.getLinkMen().add(lm1);
        lm1.setCustomer(c);
        
        session.save(lm1);
        
        //4、提交事务
        tx.commit();
        //5、关闭资源
        session.close();
    }
    
    //移除联系人
    @Test
    public void fun3() {
        //1、获得session
        Session session = HibernateUtils.openSession();
        //2、开启事务
        Transaction tx = session.beginTransaction();
        //3、操作
        //获得需要操作的客户对象
        Customer c = session.get(Customer.class, 4l);
        //获得要移除的联系人对象
        LinkMan lm = session.get(LinkMan.class, 3l);
        
        c.getLinkMen().remove(lm);
        lm.setCustomer(null);
        
        
        //4、提交事务
        tx.commit();
        //5、关闭资源
        session.close();
    }   
}

多对多:
 O 对象 两方都使用集合. 
 R 关系型数据库 使用中间表.至少两列.作为外键引用两张表的主键.
 M 映射文件 多: <set name="" table="中间表名" >
       <key column="别人引用我" />
       <man-to-many class="" column="我引用别人的" />
      </set>
      
 操作:操作管理级别属性. 
  cascade: 级联操作 
   减少我们书写的操作代码.
   none(默认值) 不级联
   save-update: 级联保存
   delete: 级联删除
   all: 级联保存+级联删除
  结论: 可以使用save-update.不推荐使用delete. 也可以不用cascade.
  inverse: 反转关系维护
   属于性能优化.必须选择一方放弃维护主键关系.哪方放弃要看业务方向.
1、表中表达

2、实体表达

3、配置文件的配置
        <!-- 多对多表达式 -->
        <!-- 
            name:集合属性名
            table:配置中间表名
            key
             |column:外键名,别人引用我的外键列名,此类对应表的外键列名
            class:this类与哪个类是多对多关系
            column:与this类有多对多关系的类的外键列名
         -->
        <set name="roles" table="sys_user_role">
            <key column="user_id"></key>
            <many-to-many class="Role" column="role_id"></many-to-many>
        </set>
        <!-- 使用inverse属性
            true:放弃维护外键关系
            结论:将来在开发中,如果遇到多对多关系,一定要选择一方放弃维护关系
            一般谁来放弃维护关系要看业务方向,例如录入员工时,需要为员工指定所属角色,
            那么业务方向就是由员工维护角色,角色不需要维护与员工的关系,角色放弃维护
         -->        
        <set name="users" table="sys_user_role" inverse="true">
            <key column="role_id"></key>
            <many-to-many class="User" column="user_id"></many-to-many>
        </set>

查询总结

1、oid查询-get
2、对象属性导航查询
3、HQL
package com.zzh.hibernate.hql;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.zzh.hibernate.domain.Customer;
import com.zzh.hibernate.utils.HibernateUtils;

public class Demo {
    //基本查询
    @Test
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer ";
        String hql2 = " from com.zzh.hibernate.domain.Customer";//完整写法 
        
        Query query = session.createQuery(hql);
        List<Customer> list = query.list();
        System.out.println(list);
        
        tx.commit();
        session.close();
    }
    
    //顺序查询
    @Test
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer order by cust_id desc";
        String hql2 = " from com.zzh.hibernate.domain.Customer";//完整写法 
        
        Query query = session.createQuery(hql);
        List<Customer> list = query.list();
        System.out.println(list);
        
        tx.commit();
        session.close();
    }
    
    //条件查询
    @Test
    public void fun3() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer where cust_id = ? ";
        String hql2 = " from Customer where cust_id = :id ";//完整写法 
        
        Query query = session.createQuery(hql);
        query.setParameter(0, 1l);
        //query.setParameter("id", 2l);
        Customer c = (Customer) query.uniqueResult();
        System.out.println(c);
        tx.commit();
        session.close();
    }
    
    //分页查询
    @Test
    public void fun4() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer";
        
        Query query = session.createQuery(hql);
        query.setFirstResult(0);
        query.setMaxResults(2);
        List<Customer> list = query.list();
        System.out.println(list);

        tx.commit();
        session.close();
    }
    
    //统计查询 count sum avg max min
    @Test
    public void fun5() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " select count(*) from Customer";
        String hql2 = " select sum(cust_id) from Customer";
        String hql3 = " select avg(cust_id) from Customer";
        String hql4 = " select max(cust_id) from Customer";
        String hql5 = " select min(cust_id) from Customer";
        
        Query query = session.createQuery(hql3);
        Number number = (Number) query.uniqueResult();
        System.out.println(number);

        tx.commit();
        session.close();
    }
    
    //投影查询
    @Test
    public void fun6() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " select cust_name from Customer";
        String hql1 = " select cust_name,cust_id from Customer";
        String hql2 = " select new Customer(cust_id,cust_name) from Customer";
        
        Query query = session.createQuery(hql2);
        List<Object[]> list = query.list();
        System.out.println(list);

        tx.commit();
        session.close();
    }
}

//HQL的多表查询
public class Demo2 {
    //回顾-原生SQL
    //交叉连接-笛卡儿积(避免)
//      select * from A,B
    //内连接
//      |-隐式内连接
    //      select * from A,B where b.aid = a.id
//      |-显式外连接
    //      select * from A inner join B on b.aid = a.id
    //外连接
//      |-左外
    //      select * from A left [outer] join B on b.aid = a.id
//      |-右外
    //      select * from A right [outer] join B on b.aid = a.id
//-------------------------------------------------------------------
    //HQL的多表查询
    //内连接(迫切)
    //外连接
//      |-左外(迫切)
//      |-右外(迫切)
    
    
    //基本语法
    @Test
    //HQL内链接=>将连接两端的对象分别返回,封装到一个数组中
    public void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer c inner join c.linkMen ";
        
        Query query = session.createQuery(hql);
        List<Object[]> list = query.list();
        for(Object[] obj :list) {
            System.out.println(Arrays.toString(obj));
        }
        
        tx.commit();
        session.close();
    }
    
    @Test
    //HQL迫切内链接=>将连接的两端对象封装到一个对象中
    public void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer c inner join fetch c.linkMen ";
        
        Query query = session.createQuery(hql);
        List<Customer> c = query.list();
            System.out.println(c);
        
        tx.commit();
        session.close();
    }
    
    @Test
    //HQL左外连接
    public void fun3() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer c left join c.linkMen ";
        
        Query query = session.createQuery(hql);
        List<Customer> c = query.list();
            System.out.println(c);
        
        tx.commit();
        session.close();
    }
    
    @Test
    //HQL右外连接
    public void fun4() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer c right join c.linkMen ";
        
        Query query = session.createQuery(hql);
        List<Customer> c = query.list();
            System.out.println(c);
        
        tx.commit();
        session.close();
    }
4、Criteria
离线Criteria查询对象

在我们的Web-Service-Dao分层开发中,在之前的学习中,对于根据不同属性/参数/查询条件查询的业务,都是在Dao层分不同的方法来实现的。如图
这就使得无法创建一个通用的方法来实现对不同的查询条件进行查询,而Hibernate则有解决这种情况的方法,即离线查询对象。

即在Web层根据查询条件创建对应Criteria对象,再逐层传递到Dao层用一个通用的查询方法来查询。
具体代码如下
/ 离线Criteria查询
public class Demo2 {

    @Test
    public void fun1() {
        //----------------------------------------------------
        // 假设这里是Web层或Service层的操作
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
        // 注意这里是用DetachedCriteria类的静态方法forClass创建离线Criteria对象
        detachedCriteria.add(Restrictions.idEq(13l));
        // 传递到下面就是Dao层的操作
        //----------------------------------------------------
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        Criteria criteria = detachedCriteria.getExecutableCriteria(session);// 使离线Criteria与Session关联(上线)获取可执行Criteria对象

        List<Customer> list = criteria.list();
        System.out.println(list);
        //----------------------------------------------------
        tx.commit();
        session.close();
    }
}
5、原生SQL

查询优化

延迟加载:session.get()和session.load()
//懒加载|延迟加载
public class Demo {
    @Test
    //get方法:立即加载,执行方法时立刻发送sql语句查询结果
    public  void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.get(Customer.class, 1l);
        System.out.println(c);
        tx.commit();
        session.close(); 
    }
    
    @Test
    //load方法:是在执行时,不发送任何sql语句,返回一个对象,使用该对象时,才执行查询
    //延迟加载:仅仅获得没有使用,不会查询,在使用时才进行查询
    //是否对类进行延迟加载:可以通过在class元素上配置lazy属性来控制
        //lazy="true" :加载时,不查询,使用时才查询
        //lazy="false" :加载时立即查询 
    public  void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.load(Customer.class, 3l);
        System.out.println(c);
        tx.commit();
        session.close(); 
    }
}
底层大概原理其实是用动态代理的方式生成一个实体类的子类对象,增强其获取属性的方法当这些获取属性的方法被调用时查询数据库返回具体的数据。(在打印一个对象的值(地址)时,若出现'$'符号,即说明这个对象是一个代理对象。
另外:创建对象关系映射的时候实体类可以为final类型,如果该实体类为final类型,hibernate将不能为该类生成一个代理对象,懒加载也就无效了,hibernate将直接发送SQL语句进行查询。
关于Hibernate的懒加载具体细节,自查。
抓取策略配置
        <!-- 
            lazy属性:决定是否延迟加载
                true:延迟加载
                false:立即加载
                extra:继续懒惰
            fetch属性:决定加载策略,使用什么类型的sql语句加载集合数据
                select(默认值):单表查询加载
                join:使用多表查询加载集合
                subselect:使用子查询加载集合
            bacth-size="3":抓取集合的数量为3
                抓取客户的集合时,一次抓取三个客户
         -->
        <set name="linkMen" lazy="true" fetch="select" bacth-size="3">
            <key column="lkm_cust_id"></key>
            <one-to-many class="LinkMan" />
        </set>

    @Test
    //集合级别的关联
    //fetch:select 单表查询
    //lazy:true 使用时才加载集合数据
    public  void fun1() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.get(Customer.class, 1l);
        Set<LinkMan> linkMen = c.getLinkMen();
        System.out.println(linkMen);
        tx.commit();
        session.close(); 
    }

    @Test
    //集合级别的关联
    //fetch:select 单表查询
    //lazy:false 立即加载集合数据
    public  void fun2() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.get(Customer.class, 1l);
        Set<LinkMan> linkMen = c.getLinkMen();
        System.out.println(linkMen);
        tx.commit();
        session.close(); 
    }
    
    @Test
    //集合级别的关联
    //fetch:select 单表查询
    //lazy:extra 极其懒惰,与懒加载效果基本一致,如果只获得集合的size,则只查询集合的size(count语句)
    public  void fun3() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.get(Customer.class, 1l);
        Set<LinkMan> linkMen = c.getLinkMen();
        System.out.println(linkMen);
        tx.commit();
        session.close(); 
    }
    
    @Test
    //集合级别的关联
    //fetch:join 多表查询
    //lazy:true|false|extra 失效,立刻加载
    public  void fun4() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        Customer c = session.get(Customer.class, 1l);
        Set<LinkMan> linkMen = c.getLinkMen();
        System.out.println(linkMen.size());
        System.out.println(linkMen);
        tx.commit();
        session.close(); 
    }
    
    @Test
    //fetch:subselect 子查询
    //lazy:true 使用时才加载集合数据
    public  void fun6() {
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        
        String hql = " from Customer ";
        Query query = session.createQuery(hql);
        List<Customer> list = query.list();
        for(Customer c:list) {
            System.out.println(c);
            System.out.println(c.getLinkMen().size());
            System.out.println(c.getLinkMen());
        }

        tx.commit();
        session.close(); 
    }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zella.domain">
    <!--配置表与实体(java实体对象)之间的关系-->
    <class name="LinkMan" table="cst_linkman">
        <id name="lkm_id" column="lkm_id">
            <generator class="native"/>
        </id>
        <property name="lkm_name"/>
        <property name="lkm_gender"/>
        <property name="lkm_phone"/>
        <property name="lkm_mobile"/>
        <property name="lkm_email"/>
        <property name="lkm_qq"/>
        <property name="lkm_position"/>
        <property name="lkm_memo"/>
        <!--
        fetch 决定加载的sql语句
            select: 使用单表查询
            join : 多表查询
        lazy  决定加载时机
            false: 立即加载
            proxy: 由customer的类级别加载策略决定.
         -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer" lazy="false" fetch="select"/>
    </class>
</hibernate-mapping>
结论
为了提高效率,fetch的选择上应该选择select,lazy的取值应该选择true,应该使用默认值
no-session问题解决:
扩大session的作用范围,使用Filter



























posted @ 2018-09-06 21:24  zzh1997  阅读(373)  评论(0)    收藏  举报