十三、hibernate对象的三种状态与懒加载机制
一、对象状态简介
1.瞬时态(transient):数据库中没有数据与之对应,超过作用域会被JVM回收,一般是new出来的且与session没有关联的对象
2.持久态(persistent):数据库中有数据与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交.(持久态对象状态发生改变,在事务提交时会影响到数据库)
3.脱管态/游离态(detached):数据库中有数据与之对应,但当前没有session与之关联,脱管对象状态发生改变,hibernate不能检测到。
Course c1=new Course();//瞬时态 c1.setCname("PHP");//瞬时态 c1.setCcredit(3);//瞬时态 c1.setCid(19);//瞬时态 Session session=HibernateUtil.getCurrentSession(); Transaction ts=null; try { session=HibernateUtil.getCurrentSession(); ts=session.beginTransaction(); session.save(c1);//持久态,此时c1处于session管理之下 c1.setCname("python");//持久态的对象状态发生改变,hibernate会检测到,并且会同步到数据库中 ts.commit(); c1.setCcredit(5);//ts已经提交,此时处于游离态,状态改变hibernate检测不到,也不会同步到数据库中 } catch (Exception e) { // TODO: handle exception e.printStackTrace(); if(ts!=null) ts.rollback(); }finally{ if(session!=null&&session.isOpen()){//事务提交或者关闭session都会使对象处于游离态 session.close(); } }
二、hibernate对象状态图
三、懒加载机制
默认情况下,xxx.hbm.xml的<class lazy=”true”>,即启用了懒加载机制。
以下情况应注意懒加载机制:
①load方法
Load先到缓存(session缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找,即不发出sql语句),等后面使用这个代理对象操作的时候,才到DB中查询(发出SQL语句),这就是我们常说的load在默认情况下支持延迟加载(lazy),如果禁用了懒加载机制,则命令Load先到缓存(session缓存/二级缓存)中去查,如果没有则立即发出SQL语句到数据库中查询。
②session外得到对象属性
Employee e=(Employee) session.get(Employee.class, 1); System.out.println(e.getName()+e.getDept().getName());
以上代码在session中执行并不会出错,但是如果我是将e返回给上一级,在别的地方处理e,例如在session外打印e.getDept().getName(),则会报错could not initialize proxy - no Session,不能初始化代理对象,没有session。其实在session外e.getName()不会报错,因为这是它本身的属性,而e.getDept().getName()需要session再发出sql语句去查,所以在session已经关闭的情况下就报错了。
这个异常有两种处理方式,
一是Department.hbm.xml的<class lazy=”false”>,关闭懒加载。
二是在得到e之后就强制session去发出sql得到e.getDept(),并绑定在e身上,此时e.getDept()也相当于是e的自身的属性了。
具体代码:
e=(Employee) session.get(Employee.class, 1); Hibernate.initialize(e.getDept());//发出sql语句得到dept所有属性