Hibernate

day1

Hibernate是开源的ORM(对象关系映射)框架。对JDBC进行轻量级的封装,将pojo和数据库表建立映射关系,是一个全自动的orm框架。它可以自动生成sql语句,自动执行。使码农可以使用面向对象的思想来操作数据库。

版本是5.0.7

hibernate
英 [ˈhaɪbəneɪt] 美 [ˈhaɪbərneɪt]
vi.
(某些动物)冬眠,蛰伏

解压后的目录:documentation:文档,API文档
lib:Hibernate编译和运行所依赖的JAR包。required子目录下的是运行hibernate必须的jar包。

书写主配置文件 hibernate.cfg.xml



<hibernate-configuration>
    <session-factory>
        
         
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driverproperty>
         
        <property name="hibernate.connection.url">jdbc:mysql:///studentproperty>
         
        <property name="hibernate.connection.username">rootproperty>
         
        <property name="hibernate.connection.password">rootproperty>
        
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>


        
        
        <property name="hibernate.show_sql">trueproperty>
        
        <property name="hibernate.format_sql">trueproperty>
        
        <property name="hibernate.hbm2ddl.auto">updateproperty>

         
         <property name="hibernate.connection.isolation">4property>

         
         <property name="hibernate.current_session_context_class">threadproperty>

        
        <mapping resource="com/hero/pojo/Customer.hbm.xml" />
        <mapping resource="com/hero/pojo/LinkMan.hbm.xml" />
        <mapping resource="com/hero/pojo/Role.hbm.xml" />
        <mapping resource="com/hero/pojo/User.hbm.xml" />
    session-factory>
hibernate-configuration>

书写orm元数据(pojo和表的映射配置文件)

class Customer { }
Customer.hbm.xml



<hibernate-mapping package="com.hero.pojo" >

<class name="Customer" table="cst_customer" >
<id name="custId" column="cust_id" >

<generator class="native">generator>
id>


<property name="custPhone" column="cust_phone" >property>


class>

hibernate-mapping>












@Test
    public void TestA() {

        //配置加载类,加载主配置,加载ORM元数据;使用空参,加载默认位置(src下的hibernate.cfg.xml)的配置文件
        Configuration conf = new Configuration().configure();
        //1.负责保存和使用所有配置信息,消耗内存很大   2.属于线程安全对象   
        //因为上面两个原因,所有保证在web项目中只有一个sessionFactory
        SessionFactory factory = conf.buildSessionFactory();
        //获得一个新的session
        Session session = factory.openSession();
        //获取并开启事务
        Transaction transaction = session.beginTransaction();

        //---------------------------------------------
        Customer customer = new Customer();
        customer.setCustName("百度");
        session.save(customer);

        //---------------------------------------------
        transaction.commit();
        //transaction.rollback();

        session.close();

        factory.close();

    }

day2

实体的规则

实体类创建注意事项:
1.要有空参构造器(底层是反射)
2.提供set/get,私有参数
private int id; //成员变量

一对set/get方法叫做一个属性,即使set/get是没有意义的,一个类中有多少个属性取决于有多少对set/get

3.持久化类中的属性,最好使用包装类型

4.持久化类需要提供oid和数据库中的主键相对应(没有主键的表是无法使用hibernate的)

5.不要用final修饰class(代理是用cglib继承的,如果用final就无法继承)


主键类型:
1.自然主键(少见,例如身份证号码)
在业务中,某个属性刚好不重复可以代表每个不同的行
2.代理主键(常见)
一个没业务意义的列,但是不重复可以代表不同的行


主键生成策略(其中)
每条记录录入的时候,主键的生成规则
1.identity 主键自增,由数据库来维护主键值,不需要指定主键值

<id name="custId" column="cust_id" >
<generator class="identity">generator>
id>

2.increment 主键自增,由hibernate来维护主键,每次插入会查询数据库,然后id+1
开发中不要用,因为有线程安全问题。而且所有的数据库都有自己的维护自增主键的算法,不要外界框架来帮忙

3.sequence:oracle中的主键生成策略
4.hilo:主键自增,由hibernate来维护主键,采用高低位算法

5.native(自动三选一:identity,sequence,hilo)

6.uuid:产生随机字符串,必须要string类型

7.assigned开发人员自己录入,自然主键

hibernate的状态

对象分为三种状态
1.瞬时态:,数据库中没有ID和你对应,没有在session中缓存,失去引用后就会被垃圾回收,永远没有你存在的痕迹
2.持久态:在提交事务后数据库有ID对应,和session有关联
3.游离态|托管状态:有Id对应,没有和session关联

Customer customer = new Customer();//没有id,没有和session关联=>瞬时态

customer.setCustName("百度");//瞬时态
        session.save(customer);//有id,有关联,持久态

        //---------------------------------------------
        transaction.commit();
        //transaction.rollback();

        session.close();//有id,没关联,游离态

        factory.close();

save方法的本质:将瞬时态对象转化成持久态对象
在session.save(customer);前打断点
如果主键生成策略是native,那么在session.save(customer);执行后会打印Insert语句,目的是为了获得ID
但是如果主键生成策略是increment
那么session.save(customer);执行后会打印,目的是为了获得ID

Hibernate: 
    select
        max(cust_id) 
    from
        cst_customer

提交事务后才会打印insert语句

如果是uuid,那么save不会打印任何语句,提交事务后才会打印insert语句


持久化:持久化状态的对象的任何变化都会自动同步到数据库中,使用hibernate的目的就是同步数据库,所以用持久态对象进行增改

Customer c = session.get(Customer.class, "2");
        System.out.println(c);
        c.setCustName("六六六");
        transaction.commit();
        session.close();
        factory.close();

上面的代码修改了c对象的属性,在提交事务后会修改数据库里的名字属性

saveOrUpdate:可以将对象转换成持久态(不管你是游离态还是瞬时态)
save:把瞬时态变成持久态
close:关闭session,把持久态变成游离态
update:把游离态变成持久态
delete:把持久态变成瞬时态
get:获得一个持久态对象


缓存

提高操作数据库的效率
查询数据库活的一个快照
持久态:其实就是在session中有缓存数据
缓存中的对象会同步到数据库中
查询数据先走缓存,如果缓存中有,就不去数据库了
但是如果数据库数据变了,hibernate是不知道的,还是去缓存,结果就会出错

隔离级别

1 0001 读未提交
2 0010 读已提交
4 0100 可重复读
8 1000 串行化

 <property name="hibernate.connection.isolation">4property>
//获取并开启事务
        Transaction transaction = session.beginTransaction();

事务在service层,需要session
dao层要用session操作数据
两个层的session必须一样

JDBC的时候要手动绑定线程
现在框架sf.getCurrentSession()


使用sf.getCurrentSession
要在主配置文件中配置

<property name="hibernate.current_session_context_class">threadproperty>

*注意:***getCurrentSession获得的session提交事务后会自动关闭session,如果你手动close那么就会抛异常

批量查询(概述)

HQL 在查询多表但是不复杂的时候用

Criteria 单表查询

SQL原生态的 适合特别特别复杂的业务


HQL查询

String hql = select 属性 from 对象完整类名

如果是select *,那么可以省略成from 对象完整类名

如果类的名字不重复,那么可以直接写类的名字,不用带包名

在Hql中,是不可以出现任何关于数据库信息的词句,完全面向对象

//基础查询
String hql = "from Customer";
        Query query  = session.createQuery(hql);
        List list = query.list(); //返回所有数据列表
        for(Customer c : list){
            System.out.println(c);
        }

        //query.uniqueResult(); 如果你知道只有一条结果
条件查询
String hql = "from Customer where custId = "+"2";
        Query query  = session.createQuery(hql);
        Customer c = (Customer) query.uniqueResult(); 
        System.out.println(c);
问号占位符
String hql = "from Customer where custId = ? ";
        Query query  = session.createQuery(hql);
        query.setString(0, "3");//0代表第一个外号,内容是“3”

        //推荐使用setParameter,不管你是什么类型都可以用
        query.setParameter(0, "3");

        Customer c = (Customer) query.uniqueResult(); 
        System.out.println(c);
//命名占位符
//如果业务使语句?的位置变化,靠顺序就难了
//为数据起一个随便的名字,格式是   :+名字
String hql = "from Customer where custId = :hero ";
        Query query  = session.createQuery(hql);

        //重载方法,赋予名字是hero值“6”
        query.setParameter("hero", "6");
        Customer c = (Customer) query.uniqueResult(); 
        System.out.println(c);
分页查询
String hql = "from Customer  ";
        Query query  = session.createQuery(hql);
        //起始行,从第几行开始抓
        query.setFirstResult(0);
        //一共呢要抓几行数据啊
        query.setMaxResults(3);
        List c = query.list();

        System.out.println(c);

criteria 英[kraɪ’tɪərɪə]
美[kraɪˈtɪrɪə]
n. (批评、判断等的) 标准,准则( criterion的名词复数 ); (criterion的复数)

criteria不用写语句,完全面向对象查询。QBC(query by Criteria)

//查询所有Customer对象
        Criteria criteria = session.createCriteria(Customer.class);

        List c = criteria.list();
        //criteria.uniqueResult();


        System.out.println(c);
//条件查询
Criteria criteria = session.createCriteria(Customer.class);

        //  Restrictions可以点出来许多sql条件

        criteria.add(Restrictions.eq("custId", "2"));

        Customer c = (Customer) criteria.uniqueResult();


        System.out.println(c);



Restrictions可以点出来许多sql条件
Hibernate_第1张图片

Hibernate_第2张图片

//分页查询
Criteria criteria = session.createCriteria(Customer.class);

        criteria.setFirstResult(0);
        criteria.setMaxResults(2);
        List c  = criteria.list();


        System.out.println(c);
//查询总行数
Criteria criteria = session.createCriteria(Customer.class);
        //projections可以点出聚合函数       
        criteria.setProjection(Projections.rowCount());

        Long c = (Long)criteria.uniqueResult();


        System.out.println(c);

原生态SQL查询

//查询所有Customer对象
        String sql = "select * from cst_customer";
        SQLQuery query = session.createSQLQuery(sql);
        //因为你写的sql,框架不知道你查的是什么类型,
        所有列表里每个数据都是object数组,存放表的每一个属性
        List<Object[]> c = query.list();
        for(Object[] objs : c){
            System.out.println(Arrays.toString(objs));
        }

楼上的方法太麻烦了,框架有解决办法

//查询所有Customer对象
        String sql = "select * from cst_customer";
        SQLQuery query = session.createSQLQuery(sql);
        //告诉框架你的实体类型
        query.addEntity(Customer.class);
        List c = query.list();
        System.out.println(c);
//占位符查询
//String sql = "select * from cst_customer limit ?,?";
        String sql = "select * from cst_customer where cust_id = ?";
        SQLQuery query = session.createSQLQuery(sql);
        //告诉框架你的实体类型
        query.addEntity(Customer.class);
        //第一个占位符值是2
        query.setParameter(0, "2");

        Customer c = (Customer) query.uniqueResult();
        System.out.println(c);

day3

Hibernate_第3张图片

上图是数据库表的表示方式,那么在POJO中如何表达?


一对一

少见

一对多|多对一

例如
客户表:id=1 name=百度 id=2 name=腾讯
职员表:id =1 name=张三 cid=1

如果POJO表达关系

class company{
private int id;
private String name;
private Set  staffs;
}

class staff{
private int id;
private String name;
private Company com;

}


//客户类:客户有百度,腾讯,阿里
public class Customer {

    private Long cust_id;

    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;

    private Set linkMans;
   }



<hibernate-mapping package="com.hero.pojo" >

    <class name="Customer" table="cst_customer" >

        <id name="cust_id"  >
            <generator class="native">generator>
        id>

        <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_linkman" column="cust_linkman" >property>
        <property name="cust_phone" column="cust_phone" >property>
        <property name="cust_mobile" column="cust_mobile" >property>

        
        <set name="linkMans" >
            <key column="lkm_cust_id">key>
            <one-to-many class="LinkMan"/>
        set>


    class>
hibernate-mapping>

//一个客户对象有多个联系人,客户公司是百度,百度的联系人有好多个
public class LinkMan {

    private Long lkm_id;

    private Character lkm_gender;
    private String lkm_name;
    private String lkm_phone;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_mobile;
    private String lkm_memo;
    private String lkm_position;

    //表达多对一关系
    private Customer customer ;
    }


<hibernate-mapping package="com.hero.pojo" >
    <class name="LinkMan" table="cst_linkman" >
        <id name="lkm_id"  >
            <generator class="native">generator>
        id>
        <property name="lkm_gender"  >property>
        <property name="lkm_name"  >property>
        <property name="lkm_phone"  >property>
        <property name="lkm_email"  >property>
        <property name="lkm_qq"  >property>
        <property name="lkm_mobile"  >property>
        <property name="lkm_memo"  >property>
        <property name="lkm_position"  >property>

        
        
          
          
        <many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
        many-to-one>
    class>
hibernate-mapping>

@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.getLinkMans().add(lm1);
        c.getLinkMans().add(lm2);

        //表达对对对,联系人属于哪个客户
        lm1.setCustomer(c);
        lm2.setCustomer(c);


        session.save(c);
        session.save(lm1);
        session.save(lm2);

        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }

@Test
    //为客户增加联系人
    public void fun2(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        //1> 获得要操作的客户对象
        Customer c = session.get(Customer.class,2L);
        //2> 创建联系人
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("张三");
        //3> 将联系人添加到客户,将客户设置到联系人中
        c.getLinkMans().add(lm1);
        lm1.setCustomer(c);
        //4> 执行保存
        session.save(lm1);
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }


级联操作:save-update,不要用delete,太危险了

@Test
    //为客户删除联系人,这里只是解除了张三作为百度联系人的属性,数据库中还是有张三的记录的
    //只是张三的外键变成了空
    public void fun3(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        Customer c = session.get(Customer.class, 2L);

        LinkMan linkMan = session.get(LinkMan.class, 5L);

        c.getLinkMans().remove(linkMan);

        linkMan.setCustomer(null);

        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }

//上面保存新增的百度联系人
//如果新增了100个,难道要一个个save么?
 session.save(c);
        session.save(lm1);
        session.save(lm2);

        <set name="linkMans" cascade="save-update" >
            <key column="lkm_cust_id">key>
            <one-to-many class="LinkMan"/>
        set>

同样的,在多的一方也可以级联操作。例如,添加了一个腾讯的李四,保存李四的同时也添加腾讯公司的信息


          
        <many-to-one name="customer" column="lkm_cust_id" class="Customer"  cascade="save-update" >
        many-to-one>
//3操作
        Customer c = new Customer();
        c.setCust_name("腾讯");

        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("李四");

        //表达一对多,客户下有多个联系人
        c.getLinkMans().add(lm1);

        //表达对对对,联系人属于哪个客户
        lm1.setCustomer(c);
        //只保存李四,不保存腾讯,但是因为级联或保存腾讯
        session.save(lm1);


下面是执行的SQL语句,添加了一个腾讯的李四,所以在表中添加腾讯customer,linkman李四

先添加腾讯信息
再添加李四信息(包含了外键腾讯,这是linkman自己维护外键)
维护外键(这是customer方维护外键)

inverse 英[ˌɪnˈvɜ:s]
美[ˌɪnˈvɜ:rs]
adj. 相反的; 逆向的; 倒转的;
n. 相反; 倒转; 相反的事物;
vt. 使倒转; 使颠倒;

很明显,最后的维护外键是不需要的,所以在配置文件中配置

Hibernate: 
    insert 
    into
        cst_customer
        (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile) 
    values
        (?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        cst_linkman
        (lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lkm_cust_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        cst_linkman 
    set
        lkm_cust_id=? 
    where
        lkm_id=?

        <set name="linkMans" cascade="save-update" inverse="true" >
            <key column="lkm_cust_id">key>
            <one-to-many class="LinkMan"/>
        set>
//这行代码也可以不用写了
//因为customer已经不维护外键了
//对象中的linkmans集合已经和我没关系了
c.getLinkMans().add(lm1);

如果customer维护外键,不设置级联,然后删除阿里对象,那么会删除从表的阿里的联系人,同时删除阿里customer

如果customer不维护外键,不置级联,然后删除阿里对象,那么会删除从表的阿里的联系人,同时删除阿里customer

多对多

//角色对象
public class Role { 
    private Long role_id;
    private String role_name;
    private String role_memo;
    //表达多对多
    private Set users = new HashSet();
    }


<hibernate-mapping package="com.hero.pojo" >
    <class name="Role" table="sys_role" >
        <id name="role_id"  >
            <generator class="native">generator>
        id>
        <property name="role_name"  >property>
        <property name="role_memo"  >property>

            
        <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>
    class>
hibernate-mapping>
public class User {

    private Long user_id;
    private String user_code;
    private String user_name;
    private String user_password;
    private Character user_state;
    //表达多对多
    private Set roles = new HashSet();
    }


<hibernate-mapping package="com.hero.pojo" >
    <class name="User" table="sys_user" >
        <id name="user_id"  >
            <generator class="native">generator>
        id>
        <property name="user_code"  >property>
        <property name="user_name"  >property>
        <property name="user_password"  >property>
        <property name="user_state"  >property>

        
        
         
        <set name="roles" table="sys_user_role" cascade="save-update" >
            <key column="user_id" >key>
            <many-to-many class="Role" column="role_id" >many-to-many>
        set>

    class>
hibernate-mapping>

操作和一对多是一样的

//这个代码出现了报错
//在配置的时候,没有配置inverse属性
//所以默认是都维护外键
//在一对多的时候,双方维护外键
//先建立主表,然后建立从表,从表顺便维护外键,在建立从表的时候写好外键数据
//然后主表维护外键,把对于的从表的外键修改成目标数据


//但是多对多
//双方都会维护中间表
//user表建立插入数据,role表建立插入数据,中间表建立
//user维护主键,让中间表插入数据
//role表维护主键,让中间表插入数据
//这样主键就冲突了
        User user1 = new User();
        User user2 = new User();

        Role role1 = new Role();
        Role role2 = new Role();

        user1.setUser_name("李彦宏");
        user2.setUser_name("麻花藤");

        role1.setRole_name("保安");
        role2.setRole_name("保镖");

        user1.getRoles().add(role1);
        user1.getRoles().add(role2);

        user2.getRoles().add(role1);
        user2.getRoles().add(role2);

        role1.getUsers().add(user1);
        role1.getUsers().add(user2);

        role2.getUsers().add(user1);
        role2.getUsers().add(user2);

        session.save(user1);
        session.save(user2);
        session.save(role1);
        session.save(role2);

        //-------------------------------------------------
        //4提交事务
        tx.commit();

解决办法1:java代码少些一半,不写

role1.getUsers().add(user1);
        role1.getUsers().add(user2);

        role2.getUsers().add(user1);
        role2.getUsers().add(user2);

这样只有一方维护外键了

解决办法2:inverse
写上面的java代码,但是配置中让某一方放弃维护


//为郝强勇新增一个角色
//3操作
        //1> 获得郝强勇用户
        User user = session.get(User.class, 1l);
        //2> 创建公关角色
        Role r = new Role();
        r.setRole_name("男公关");
        //3> 将角色添加到用户中
        user.getRoles().add(r);
        //在user中配置级联,那么就不用下面的保存角色代码了
        //4> 将角色转换为持久化
        //session.save(r);
        //-------------------------------------------------
        //4提交事务
//为郝强勇解除一个角色
//3操作
        //1> 获得郝强勇用户
        User user = session.get(User.class, 1l);
        //2> 获得要操作的角色对象(保洁,保安)
        Role r1 = session.get(Role.class, 1l);
        Role r2 = session.get(Role.class, 2l);
        //3> 将角色从用户的角色集合中移除
        user.getRoles().remove(r1);
        user.getRoles().remove(r2);

        //-------------------------------------------------
        //4提交事务

day4

查询


查询总结

五种查询:
1.oid查询 : get (customer.class,1L) 根据主键
2.对象属性导航查询 :根据customer对象,通过getLinkMan()方法来查询联系人
3:HQL
4:criteria
5:原生态SQL

前两种太简单了,SQL也不用讲

查询HQL

//如果没有重复的类名,可以省略包名
        String hql = "from Customer";

        Query query = session.createQuery(hql);

        List<Customer> list = query.list();

        System.out.println(list);
//查询所有表,没什么卵用,还可能死机
String hql = "from java.lang.Object";

//不可以出现数据库表的字段,必须是类中的属性字段
//根据cust_id排序
String hql = "from Customer order by cust_id asc ";
String hql2 = "from Customer order by cust_id desc ";
//统计查询
        String hql = "select count(*) from Customer ";
        String hql2 = "select avg(cust_id) from Customer ";
        String hql3 = "select sum(cust_id) from Customer ";
        String hql4 = "select max(cust_id) from Customer ";
        String hql5 = "select min(cust_id) from Customer ";
String hql = "select cust_id from Customer ";
查询出的结果是List<string>
String hql = "select cust_id,cust_name from Customer ";
查询出的结果是List<Object[]>
//你不想用List来接受,想用对象customer对象来接受
//这个时候一定要有构造器Customer(cust_id,cust_name){}
//同时还要有空参构造器
String hql = "select new Customer(cust_id,cust_name) from Customer ";

hql多表查询,HQL的语句进行多表查询用的比较少,因为语法比较诡异


//学习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.linkMens ";

        Query query = session.createQuery(hql);

        List list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        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.linkMens ";

        Query query = session.createQuery(hql);

        List list = query.list();

        System.out.println(list);
        //----------------------------------------------------
        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.linkMens ";

        Query query = session.createQuery(hql);

        List list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        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.linkMens ";

        Query query = session.createQuery(hql);

        List list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();

    }

}

查询criteria

//排序
        Criteria criteria = session.createCriteria(Customer.class);

        //criteria.addOrder(Order.asc(""));
        criteria.addOrder(Order.desc("cust_id"));

        List list = criteria.list();

离线查询

查询优化

1.类级别查询(单表查询,查询一个类)
懒加载|延迟加载
get没有策略
load应用类级别的加载策略,默认是懒加载
使用对象的时候session必须是没有被关闭的
建议使用load

//get方法,是执行后立即执行SQL语句
Customer c = session.get(Customer.class,2L);
//get不具有懒加载的功能
//load方法的作用是和get一样的,但是他是延迟加载的
Customer c = session.load(Customer.class,2L);
//在使用到对象的时候才会打印SQL语句
syso(c)
// 是否对类进行延迟加载: 可以通过在class元素上配置lazy属性来控制.
        //lazy:true  加载时,不查询.使用时才查询b(默认是true)
        //lazy:false 加载时立即查询.
//如果在session关闭后才使用对象,就会空指针

2.关联级别查询
集合策略,根据customer取linkman,早customer中配置

//集合级别的关联
Customer c = session.get(Customer.class, 2l);

        Set linkMens = c.getLinkMens();//关联级别

        System.out.println(linkMens);
<class name="Customer" table="cst_customer" lazy="false" >
        <id name="cust_id"  >
            <generator class="native">generator>
        id>
        <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_linkman" column="cust_linkman" >property>
        <property name="cust_phone" column="cust_phone" >property>
        <property name="cust_mobile" column="cust_mobile" >property>

     
        <set name="linkMens" lazy="" fetch="" batch-size="3"  >
            <key column="lkm_cust_id" >key>
            <one-to-many class="LinkMan" />
        set>
class>
//默认就是这种方式
//集合级别的关联
    //fetch:select 单表查询
    //lazy:true 使用时才加载集合数据.
    Customer c = session.get(Customer.class, 2l);

        Set linkMens = c.getLinkMens();//关联级别

        System.out.println(linkMens);
///集合级别的关联
        //fetch:select 单表查询
        //lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句)
Customer c = session.get(Customer.class, 2l);

            Set linkMens = c.getLinkMens();//关联级别

            System.out.println(linkMens.size());

            System.out.println(linkMens);
//集合级别的关联
        //fetch:join    多表查询,一次性多个表全部查,所以lazy失效
        //lazy:true|false|extra 失效.立即加载
Customer c = session.get(Customer.class, 2l);

            Set linkMens = c.getLinkMens();//关联级别

            System.out.println(linkMens.size());

            System.out.println(linkMens);
//fetch: subselect 子查询
        //lazy: true 懒加载

String  hql = "from Customer";

            Query query = session.createQuery(hql);

            List list = query.list();

            for(Customer c:list){
                System.out.println(c);
                System.out.println(c.getLinkMens().size());
                System.out.println(c.getLinkMens());
            }
//fetch: subselect 子查询
        //lazy: false 立即加载
String  hql = "from Customer";

            Query query = session.createQuery(hql);

            List list = query.list();

            for(Customer c:list){
                System.out.println(c);
                System.out.println(c.getLinkMens().size());
                System.out.println(c.getLinkMens());
            }
//fetch: subselect 子查询
        //lazy: extra 极其懒惰
String  hql = "from Customer";

            Query query = session.createQuery(hql);

            List list = query.list();

            for(Customer c:list){
                System.out.println(c);
                System.out.println(c.getLinkMens().size());
                System.out.println(c.getLinkMens());
            }

关联属性策略

根据linkman取customer

<class name="LinkMan" table="cst_linkman" >
        <id name="lkm_id"  >
            class="native">
        id>
        <property name="lkm_gender"  >property>
        <property name="lkm_name"  >property>
        <property name="lkm_phone"  >property>
        <property name="lkm_email"  >property>
        <property name="lkm_qq"  >property>
        <property name="lkm_mobile"  >property>
        <property name="lkm_memo"  >property>
        <property name="lkm_position"  >property>
        -- 
        fetch 决定加载的sql语句
            select: 使用单表查询
            join : 多表查询
        lazy  决定加载时机
            false: 立即加载
            proxy: 由customer的类级别加载策略决定.
         -->
    to-one name="customer" column="lkm_cust_id" 
    class="Customer" fetch="join" lazy="proxy"  >
        to-one>
    class>

结论
为了提高效率,fetch的值选择select(也就是默认值)
lazy 的取值选择true(也就是默认值)
总之,不用配置

所以这里有lazy的no-session问题
如果session关闭后,才使用对象,懒加载的对象就空指针了
web层使用对象,但是dao层的session已经关闭了
解决办法:扩大session作用范围,原来是包裹service的范围,现在扩大到包裹三层
使用过滤器,包裹web层

批量抓取()


        <set name="linkMens" lazy="" fetch="" batch-size="3"  >
            <key column="lkm_cust_id" >key>
            <one-to-many class="LinkMan" />
        set>
String  hql = "from Customer";

            Query query = session.createQuery(hql);

            List list = query.list();
            //查询到所有的customer,遍历出来
            //每个customer对象中的集合,会一条条发送SQL(where 外键=“”)
            //配置了batch-size后,就是一次性3条SQL语句发送过去
            for(Customer c:list){
                System.out.println(c);
                System.out.println(c.getLinkMens().size());
                System.out.println(c.getLinkMens());
            }

你可能感兴趣的:(框架)