Hibernate 一级缓存测试分析
Hibernate的一级缓存就是指Session缓存,此Session非http的session会话技术,可以理解为JDBC的Connection,连接会话,Session缓存就是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先使用对象的OID(Object ID
)在Hibernate 的一级缓存空间进行查找,如果通过OID匹配到了对象,就直接从一级缓存中取出使用,如果没有找到匹配该OID值的对象,这才会进行查询数据库。当从数据库中查询数据的时候,该数据就会被放入到Session缓存中,目的就是为了减少数据库的访问次数,从而提高性能。
Hibernate缓存特点
- 当应用程序调用Session接口的 save(), update(), saveOrUpdate() 时候,如果缓存中没 有相应的对象,Hb就会自动的把查询信息加入到缓存。
- 当应用程序调用Session接口的 load(), get(), list() 等查询方法的时候,会进行判断缓存中是否有数据,同摘要。
- 当应用程序调用Session接口的 close() Session缓存会被清空
接下来进行测试一级缓存
首先测试一级缓存是否存在?对user表的主键为“1”的分别进行两次查询:
public void demo1 (){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
User user1 = session.get(User.class, "1");
System.out.println(user1);
System.out.println("-------------");
User user2 = session.get(User.class, "1");
System.out.println(user2);
System.out.println(user1 == user2);
transaction.commit();
session.close();
}
运行结果:
我们发现第一次执行Session的get()方法的时候,由于一级缓存中没有数据,所以会向数据库发送一条sql语句进行查询,第二次调用get()的时候,则不会发送sql语句,而是从一级缓存中取的,所以user和user2的内存地址相等
一级缓存的快照区
Hibernate向一级缓存放入数据的时候,同时复制一份放到Hibernate快照中,当使用commot()提交事务的时候,同时会清理Session的一级缓存,这是会用OID
判断一级缓存中的对象和快照中的对象是否一致,如果一致则执行 update 语句,将缓存中的内容同步到数据库,并且更新快照,这也就实现了不使用 update 语句就可以自动更新数据库,Hibernate快照的作用也就是为了保持缓存中的数据和数据库中的数据的一致性。
快照区代码测试
我们在get的时候设置断点,看到右侧变量 session->persitenceContext->entitlxxx->head,也就是缓存中是为空的
现在继续执行
我们发现在缓存区域已经有了数据了,同时Hibernate 也会在快照区域创建数据,在 Hibernate3 里面它使用的是Map进行存储的,map的key作为一级缓存去,value作为一级快照区,当进行查询的时候,会同时给缓存和快照去放入相同的数据,当orm对象属性发生变化的时候,会首先改变缓存区的值,当进行事务提交的时候,会比较缓存和快照的内容,如果一致则不操作,不一致则更新数据库。
继续执行:
commin()的时候,自动进行更新,clear().evict()的时候会清除缓存(删除表中数据的时候也会)
public void demo1 (){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
User user1 = session.get(User.class, "1");
System.out.println(user1);
System.out.println("-------------");
session.clear();
User user2 = session.get(User.class, "1");
System.out.println(user2);
System.out.println(user1 == user2);
transaction.commit();
session.close();
}
输入如下:
Hibernate:
select
user0_.uid as uid1_1_0_,
user0_.name as name2_1_0_,
user0_.username as username3_1_0_,
user0_.password as password4_1_0_,
user0_.email as email5_1_0_,
user0_.telephone as telephon6_1_0_,
user0_.sex as sex7_1_0_
from
user user0_
where
user0_.uid=?
User{uid=1, username=baiChaoHua, password=null, name=null, email=null, telephone=null, birthady=null, sex=null, state=0, code=null}
-------------
Hibernate:
select
user0_.uid as uid1_1_0_,
user0_.name as name2_1_0_,
user0_.username as username3_1_0_,
user0_.password as password4_1_0_,
user0_.email as email5_1_0_,
user0_.telephone as telephon6_1_0_,
user0_.sex as sex7_1_0_
from
user user0_
where
user0_.uid=?
User{uid=1, username=baiChaoHua, password=null, name=null, email=null, telephone=null, birthady=null, sex=null, state=0, code=null}
false
可以看出执行执行了两次sql,user对象的内存地址也就自然不一样
一级缓存常用的API:
clear()
:清空一级缓存。evict()
:清空一级缓存中指定的某个对象。refresh()
:重新查询数据库,用数据库中的信息来更新一级缓存与快照区。
未完待续...