Hibernate查询会先从一级缓存session中查询数据,如果session中没有会从sessionfactory中查找数据,如果前面两个都没有将从DB中查数据,这就是Hibernate的缓存机制,这样可以降低应用程序与物理数据源的交互频率,提高应用程序的性能。另外懒惰加载,就是尽可能晚的将数据库中的数据加载到内存中来,需要查询时查询数据,不需要查询的数据暂时就不查询。
一级缓存session管理方法
(1)evict(Object):将对象Object从session中清除掉,从持久状态进入到游离状态
(2)clear():将session中的所有对象都清除掉
(3)flush():将缓存中的数据与数据库中的数据进行同步
(4)contains(Object):判断session中是否包含某个对象Object
(6)将保存的数据放到session:save()
(7)将查询的数据放到session:get(),load(),HQL查询
下面以一个案例进行分析,先使用get方法到一个对象存到session中,然后再重复一遍get动作,比较两个对象是否相同,如果相同说明第二次是从缓存中取出。
具体的hibernate.cfg.xml,表和实体类参考上一篇博客,这里直接调用测试方法进行测试,看看两次get得到的对象是否是同一个内存地址,如果是true说明就是同一对象。
package TestCase; import java.util.List; import java.util.Set; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import Entity.book; import Entity.user; /** * 测试Hibernate关联查询 * @author yangchaolin */ public class testHibernate { public static Session getSession() { //读取hibernate.cfg.xml配置文件 Configuration cfg=new Configuration(); cfg.configure("hibernate.cfg.xml"); //创建sessionfactory SessionFactory factory=cfg.buildSessionFactory(); //创建session Session session=factory.openSession(); return session; } //测试session缓存机制 @Test public void testSession() { //获取session Session session=getSession(); //开启事务 Transaction trans=session.beginTransaction(); trans.begin(); //执行持久层操作 user u1=(user) session.get(user.class, 1);//查询id为1的user //提交事务 //trans.commit(); //重复获取user对象的操作 user u2=(user) session.get(user.class, 1); System.out.println("两个是否相同"+(u1==u2)); /** * 测试发现结果为true,说明二次取得是保存在session中的数据 */ //关闭session session.close(); } }
测试结果:
从测试结果来看,第二次获取是从session一级缓存中获取的,并不是从DB中取出新存到内存中的对象,两者内存地址一致,输出结果为true。
懒惰加载
参考获取user为1的数据后,先打印user的id和name属性,后面再打印user的book属性,控制台发现先查询得到user 的id和name,当后面需要输出book时,再从数据库查询book,说明数据查询分了2次,不是一次性查询得到,这种现象就是懒惰加载。
映射文件中配置lazy属性到set标签下
<!-- lazy设置为false,代表不懒惰加载,默认是懒惰加载 --> <set name="books" lazy="true"><!-- 实体类对应属性名 --> <key column="user_id"></key> <one-to-many class="Entity.book"></one-to-many> </set>
package TestCase; import java.util.List; import java.util.Set; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import Entity.book; import Entity.user; /** * 测试Hibernate关联查询 * @author yangchaolin * */ public class testHibernate { public static Session getSession() { //读取hibernate.cfg.xml配置文件 Configuration cfg=new Configuration(); cfg.configure("hibernate.cfg.xml"); //创建sessionfactory SessionFactory factory=cfg.buildSessionFactory(); //创建session Session session=factory.openSession(); return session; } //测试获取user id为1的用户的信息 @Test public void test() { //读取hibernate.cfg.xml配置文件 Configuration cfg=new Configuration(); cfg.configure("hibernate.cfg.xml"); //创建sessionfactory SessionFactory factory=cfg.buildSessionFactory(); //创建session Session session=factory.openSession(); //创建一个事务并开启事务 Transaction trans=session.getTransaction(); trans.begin(); //开始执行持久层操作 user user=(user) session.get(user.class, 1);//1代表user的id属性值 System.out.println(user.getId()); System.out.println(user.getName()); Set<book> books=user.getBooks(); for(book book:books) { System.out.println(book); } //关闭session session.close(); } }
打印结果:
当将set标签下lazy设置为true,可以看出来先查询出来id和name,当需要打印book时,才查询books属性,它的查询分了两次,这就是懒惰加载,你不需要我不加载你需要时我再加载。
现在有个问题,如果第二次查询时,session提前关闭了会怎么样?结果是第二次将查询不到数据,为了避免因为懒惰加载和session提前关闭对查询结果的影响,struts2中有一个filter专门用于提前开启session,避免因为session提前关闭查询不到数据的情况,后面有机会再了解。
结论
Hibernate下无论是缓存机制还是懒惰加载,都是为了提高性能,因为其减少了应用程序对数据源的访问。
原文地址:https://www.cnblogs.com/youngchaolin/p/10909771.html