hibernate(3)(对象的状态,一级缓存,懒加载)

对象的状态:

 临时:new出 ;对象不在session管理,与数据库无对应的记录
 持久:对象在session管理, 与数据库有对应的记录
      有oid
      对对象修改会同步到数据库
 游离:对象不在session管理,但与数据库有对应的记录. 
      修改对象,不会影响数据库

    当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态。

    处于持久化状态的对象,当对对象属性进行更改的时候,会反映到数据库中!

Hibernate中缓存分类:

         一级缓存
         二级缓存

 一级缓存:

目的:减少对数据库的访问次数!从而提升hibernate的执行效率!

1)Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数!  只在session范围有效! Session关闭,一级缓存失效!
2)当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中。 
3)Session的缓存由hibernate维护,如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。

特点:

 只在(当前)session范围有效,作用时间短,效果不是特别明显!
 在短时间内多次操作数据库,效果比较明显!

缓存相关几个方法的作用:

session.flush();       让一级缓存与数据库同步
session.evict(arg0);   清空一级缓存中指定的对象
session.clear();       清空一级缓存中缓存的所有对象

用于批量操作,比如:大量数据更新,不想缓存这些对象,可以先flush再clear。

public class Test{    
    private static SessionFactory sf;
    static {
        sf = new Configuration()
            .configure()
            .addClass(User.class)   // 测试时候使用
            .buildSessionFactory();
    }
    @Test
    public void testCache() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        User user = null;
        // 查询
        user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取
        user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取
        
        session.getTransaction().commit();
        session.close();
    }            
    @Test
    public void flush() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        
        User user = null;
        user = (User) session.get(User.class, 5);
        user.setUserName("Jack");
        // 缓存数据与数据库同步
        session.flush();
        
        user.setUserName("Jack_new");
        
        session.getTransaction().commit();  // session.flush();
        session.close();
    }    
    @Test
    public void clear() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        
        User user = null;
        // 查询
        user = (User) session.get(User.class, 5);
        // 清空缓存内容 
//        session.clear(); // 清空所有
        session.evict(user);// 清除指定
        
        user = (User) session.get(User.class, 5);
                
        session.getTransaction().commit();  // session.flush();
        session.close();
    }    
    @Test
    public void sessionTest() throws Exception {
        Session session1 = sf.openSession();
        session1.beginTransaction();
        Session session2 = sf.openSession();
        session2.beginTransaction();
        
        // user放入session1的缓存区
        User user = (User) session1.get(User.class, 1);
        // user放入session2的缓存区
        session2.update(user);
        
        // 修改对象
        user.setUserName("New Name");  // 2条update                        
        session1.getTransaction().commit();  // session1.flush();
        session1.close();
        session2.getTransaction().commit();  // session2.flush();
        session2.close();
    }
}
View Code

 补充:

1.不同的session有自己的缓存区,

User1  u1 = Session1.get(User.class,1);   把u1对象放入session1的缓存
Session2.update(u1);                      把u1放入session2的缓存
//修改对象,
U1.setName(‘new Name’);

提交事务时候,生成2条update sql,分别更新不同的session缓存区对象(这种情况应该是同一个对象,如果是两个session获取那么应该是不同的两个值一样的对象

2. list与iterator查询的区别?

list() :

一次把所有的记录都查询出来,
会放入缓存(会将对象分别放入缓存),但不会从缓存中获取数据(第二次执行list仍然执行查询数据库

Iterator():

N+1查询;N表示所有的记录总数
        即会先发送一条语句查询所有记录的主键(1),
        再根据每一个主键再去数据库查询(N)!
会放入缓存(只会将查询的对象进行缓存),也会从缓存中取数据!(第二执行iterator仍然会执行查询所有的主键,主键对应的对象会从缓存中取

 测试实例:

public class Test{    
    private static SessionFactory sf;
    static {
        sf = new Configuration()
            .configure()
            .addClass(User.class)   // 测试时候使用
            .buildSessionFactory();
    }
    //1.  list 方法
    @Test
    public void list() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        // HQL查询
        Query q = session.createQuery("from User ");
        // list()方法
        List<User> list = q.list();
        
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i));
        }        
        session.getTransaction().commit();  
        session.close();
    }
    
    //2. iterator 方法
    @Test
    public void iterator() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        // HQL查询
        Query q = session.createQuery("from User ");
        // iterator()方法
        Iterator<User> it = q.iterate();
        while(it.hasNext()){
            // 得到当前迭代的每一个对象
            User user = it.next();
            System.out.println(user);
        }
                        
        session.getTransaction().commit();  
        session.close();
    }
        
    //3. 缓存
    @Test
    public void cache() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        
        /**************执行2次list*****************
        Query q = session.createQuery("from User");
        List<User> list = q.list();      // 【会放入?】
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i));
        }
        System.out.println("=========list===========");
        list = q.list();                // 【会放入?】
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i));
        }
        
        /**************执行2次iteator******************/
        Query q = session.createQuery("from User ");
        Iterator<User> it = q.iterate();        // 【放入缓存】
        while(it.hasNext()){
            User user = it.next();
            System.out.println(user);
        }
        System.out.println("==========iterate===========");
        it = q.iterate();                        // 【也会从缓存中取】
        while(it.hasNext()){
            User user = it.next();
            System.out.println(user);
        }
        
        session.getTransaction().commit();  
        session.close();
    }
    
    // 测试list方法会放入缓存
    @Test
    public void list_iterator() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        
        // 得到Query接口的引用
        Query q = session.createQuery("from User ");
        
        // 先list  【会放入缓存,但不会从缓存中获取数据】
        List<User> list = q.list(); 
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i));
        }
        
        // 再iteraotr  (会从缓存中取)
        Iterator<User> it = q.iterate();
        while(it.hasNext()){
            User user = it.next();
            System.out.println(user);
        }
        
        session.getTransaction().commit();  
        session.close();
    }
}
View Code

1.list方法执行的查询语句:(只执行一次sql,一次性查询出所有记录)

2.iterator方法执行的查询语句:(首先查询出所有id,然后再分别查询出所有记录)

3.执行两次list方法,执行2条sql语句:(每次都是一次性查询出所有记录,缓存的却是单个对象,所以执行两次sql语句)

4.执行两次iterator:(第二次执行时候,之后执行查询所有id,单个对象都从缓存中取)

5.先执行list在执行iterator(单个取的时候,取得的list执行时候缓存的单个对象)

 

懒加载:

1.类的懒加载,在使用类的属性才加载
2.类的属性集合的懒加载,该属性集合是关联的其他表的数据,在使用该集合属性才加载。

get、load方法区别?

get: 及时加载,只要调用get方法立刻向数据库查询
load:默认使用懒加载,当用到数据的时候才向数据库查询。

当采用load方法时候,可以通过配置的lazy属性不采用懒加载的方式(默认省略时,lazy是true表示采用懒加载;false时同get方法效果):

懒加载:(lazy)

概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!

当使用懒加载时,如果session关闭后,使用懒加载数据报错

为什么要关闭session:因为数据库的连接数是有限制,关闭session,相当释放连接。

出现的异常是:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

解决session关闭后不能使用懒加载数据的问题?

方式1:先使用一下数据

          //dept.getDeptName();

方式2:强迫代理对象初始化

          Hibernate.initialize(dept);

方式3:关闭懒加载

         设置lazy=false;

方式4: 在使用数据之后,再关闭session!

实例:

Dept.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.b_one2Many">
    
    <class name="Dept" table="t_dept" >
        <id name="deptId">
            <generator class="native"></generator>
        </id>    
        <property name="deptName" length="20"></property>
        
        <!-- 
            集合属性,默认使用懒加载 
            lazy
                true 懒加载
                extra 懒加载(智能)
                false 关闭懒加载
        
        -->
         <set name="emps" lazy="extra">
              <key column="dept_id"></key>
              <one-to-many class="Employee"/>
         </set>         
         
    </class>
    
</hibernate-mapping>
View Code

Dept.java

public class Dept {

    private int deptId;
    private String deptName;
    // 【一对多】 部门对应的多个员工
    private Set<Employee> emps = new HashSet<Employee>();
    
    public int getDeptId() {
        return deptId;
    }
    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public Set<Employee> getEmps() {
        return emps;
    }
    public void setEmps(Set<Employee> emps) {
        this.emps = emps;
    }
View Code

Employee.java

private int empId;
    private String empName;
    private double salary;
    // 【多对一】员工与部门
    private Dept dept;;
    
    
    public int getEmpId() {
        return empId;
    }
    public void setEmpId(int empId) {
        this.empId = empId;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
View Code

Employee.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.b_one2Many">
    
    <class name="Employee" table="t_employee">
        <id name="empId">
            <generator class="native"></generator>
        </id>    
        <property name="empName" length="20"></property>
        <property name="salary" type="double"></property>
        
        <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one>
         
    </class>    

</hibernate-mapping>
View Code

测试:

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及时查询
        // dept = (Dept) session.get(Dept.class, 9);
        // System.out.println(dept.getDeptName());
        
        // load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
        dept = (Dept)session.load(Dept.class, 9);

//如果不使用下面处理方式,关闭session,再获取该对象对应的数据会报错
// 方式1: 先使用一下数据 //dept.getDeptName();//此时才查询数据库 // 方式2:强迫代理对象初始化 Hibernate.initialize(dept);//此时才查询数据库 // 方式3:关闭懒加载 ;类的映射配置lazy=false session.getTransaction().commit(); session.close(); // 在这里使用 System.out.println(dept.getDeptName());//

 上面是类的懒加载,还有一种类集合属性的懒加载:

        Session session = sf.openSession();
        session.beginTransaction();
//默认是不会查询集合属性的数据(默认是懒加载) Dept dept
= (Dept) session.get(Dept.class, 10); System.out.println(dept.getDeptName()); System.out.println("------");
//默认查询属性集合的数据是所有记录而不是数量 System.
out.println(dept.getEmps().isEmpty()); // 此时才执行SQL(查询employ表的数据) session.getTransaction().commit(); session.close();

可以通过配置lazy属性来设置是否懒加载

lazy 值的含义:

    true    使用懒加载
    false   关闭懒加载,意味查询类的数据时候会同时获取关联的所以纪录数据
    extra   (在集合数据懒加载时候提升效率)
            在真正使用数据的时候才向数据库发送查询的sql;
            如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

当lazy=extra,执行dept.getEmps()的size()/isEmpty()方法,查询的只是数量

当具体用到数据

 System.out.println(dept.getEmps());

才会查询所有的纪录:

 

posted @ 2017-03-22 17:23  假程序猿  阅读(201)  评论(0)    收藏  举报