复习 - 持久化环境相关的其他API (clear, evict, setReadyOnly)和FlushMode
前面的一些复习提到了Hiberante的自动脏数据检查功能,他的实质是会保存对象的一个快照,这个功能固然很好很强大,但是一旦数据量比较大,那么快照所需的空间也会比较大,所以我们可能需要在合适的时候进行手动的清理,来确保不会OutOfMemory
有下面几种可以清理的session中的对象或是阻止生成快照的方法
1. evict
这个方法就是将session中的对象(persist状态)清理出去,让他变成detached状态. 这样在session级别的缓存中就不会有该对象存在,如果查询同一条数据库中的数据,会重新生成查询语句加载,例子如下:
package com.yxy.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.yxy.bean.Student; public class HibernateClearTest { public static void main(String[] args){ SessionFactory sessionFactory = HibernateUtils.getSessionFactory(); Session session = sessionFactory.openSession(); session.getTransaction().begin(); Student s1 = (Student)session.get(Student.class, 1); session.evict(s1); Student s2 = (Student)session.get(Student.class, 1); session.getTransaction().commit(); session.close(); } }
可以在控制台看到加载s2,虽然对应的是数据库中的同一条记录,但是重新生成了select语句,说明一级缓存中的对象已经被清理出去了.
Hibernate: /* load com.yxy.bean.Student */ select student0_.id as id0_0_, student0_.name as name0_0_, student0_.sex as sex0_0_, student0_.register_date as register4_0_0_ from student student0_ where student0_.id=? Hibernate: /* load com.yxy.bean.Student */ select student0_.id as id0_0_, student0_.name as name0_0_, student0_.sex as sex0_0_, student0_.register_date as register4_0_0_ from student student0_ where student0_.id=?
2. clear
clear针对的是session中的所有对象. 原理同evict一样,同样的是让所有persist状态的对象全部变成detached状态,移出persistent context环境. 这样就不会对该对象生成快照,从而避免了脏数据检查. 节省了空间, 例子:
package com.yxy.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.yxy.bean.Student; public class HibernateClearTest { public static void main(String[] args){ SessionFactory sessionFactory = HibernateUtils.getSessionFactory(); Session session = sessionFactory.openSession(); session.getTransaction().begin(); Student s1 = (Student)session.get(Student.class, 1); session.clear(); s1.setName("update detached object"); session.getTransaction().commit(); session.close(); } }
从控制台可以看到没有生成update sql,仅有一条加载的sql, 而且数据库中的数据也没有被更新,这是因为s1已经是detached状态,当事务提交时并不会对detached状态的对象进行检查,所以更新不会同步到数据库中.
Hibernate: /* load com.yxy.bean.Student */ select student0_.id as id0_0_, student0_.name as name0_0_, student0_.sex as sex0_0_, student0_.register_date as register4_0_0_ from student student0_ where student0_.id=?
3. setReadOnly
顾名思义,setReadOnly会将对象设置成只读的,所以hiberante不会因为对该对象做了update就对其进行脏数据检查从而同步到数据库,Hiberante不会对设置成readonly的对象做脏数据检查,但是设置成只读的对象并没有在session中被清除掉,不像clear和evict那样.
例子:
package com.yxy.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.yxy.bean.Student; public class HibernateClearTest { public static void main(String[] args){ SessionFactory sessionFactory = HibernateUtils.getSessionFactory(); Session session = sessionFactory.openSession(); session.getTransaction().begin(); Student s1 = (Student)session.get(Student.class, 1); /* * set to read only */ session.setReadOnly(s1, true); /* * s1 will not be removed from session cache, so when call this statement, no need load again. */ Student s2 = (Student)session.get(Student.class, 1); /* * because s1 is read only, so will not flush this update to db when the transaction is commit */ s1.setName("update detached object"); session.getTransaction().commit(); session.close(); } }
可以看到生成的log不会重复加载,也不会生成update sql
Hibernate: /* load com.yxy.bean.Student */ select student0_.id as id0_0_, student0_.name as name0_0_, student0_.sex as sex0_0_, student0_.register_date as register4_0_0_ from student student0_ where student0_.id=?
另外,就是要记住Hibernate的几种FlushMode
1. FlushMode.AUTO
特点: 是Hibernate的默认行为, 当事务被提交或者是发生查询时,会flush脏数据到db
2. FlushMode.COMMIT
特点: 只有在事务被提交或调用session.flush()才会flush脏数据到db
3. FlushMode.MANUAL
特点: 只有在调用session.flush()时才会flush脏数据到db.