Hibernate的缓存
缓存无论对于应用服务器还是对于数据库服务器来说,都是一个福音,缓存可以减轻数据库的压力,提高查询效率。下面就具体的来介绍一下Hibernate 中的缓存吧。
缓存研究的内容
- 缓存的生命周期
- 把一个对象放入到缓存中
- 把一个对象从缓存中提取出来
- 把一个对象从缓存中清除
- 把一些对象从缓存中清除
- 把缓存中的数据同步到数据库中
- 把数据库中的数同步到缓存中
数据缓存
数据缓存一般是一个Map
对象缓存
1. 对象缓存是一个集合。而不是一个Map
2. 每个对象都是一个唯一的标识符
3. 在Hibernate中,该标识符为主键
一级缓存
说明
- 一级缓存是session缓存
- 当session开启的时候,一级缓存起作用,当session关闭的时候,一级缓存销毁了
- session 的缓存存放的是私有数据
操作
将对象放入一级缓存
get方法
|
|
说明: Session.get 方法把一个对象放入到一级缓存中
下图为上述代码执行后,hibernate执行的SQL语句,从中可以看出,只是对数据库执行了一次的查询操作。
statictis方法:统计方法
|
|
说明: 上面的代码中,session的一级缓存中存放了两个对象
下图中通过统计方法可以知道此时的一级缓存中是有两个对象(从数据库中查询出两个)。
save方法
|
|
说明: session.save() 方法把对象放入到一级缓存中了
把一个对象从一级缓存中清除
evict方法
|
|
上述代码执行的时候,hibernate输出如下的SQL语句:
说明,session调用了evict()方发法之后,一级缓存中的对象就被清除了。
clear方法
|
|
很显然,当执行session.clear()方法的时候,一级缓存中对象所有都清除掉了。
close方法
当执行session.close方法的时候,一级缓存的生命更周期结束了。
把数据库的数据同步到缓存中
refresh方法
|
|
把缓存中的数据同步到数据库中
flush方法
|
|
说明:
当执行flush() 方法的时候,Hibernate会检查一级缓存中所有的持久化转态的对象,如果该持久化状态的对象没有标识符的值,则会发出insert语句,如果该持久化状态的对象有标识符的值,则会对照副本,看是否和副本一致,如果一致,则什么都不做,如果不一致,则发出update语句
执行上述代码的时候hibernate执行如下的SQL语句:
总结
一级缓存提供了一个临时存放对象的一个内存结构,当Hibernate对对象进行操作的时候,仅仅改变的是对象的属性,改变的是一级缓存中的对象的属性,在seeesion.flush之前的代码可以任意写,因为这个时候,并没有和数据库交互。当执行session.flush的时候,Hibernate会检查一级缓存中的对象的情况,发出insert或者update语句。
Session的产生方式
需求
转账的需求:后台有一张表:account表(aid, account,money), 操作将account为1的账号转移100元到account2中。
实现:
说明: 这样的写法是不对的,因为在这两个方法中开启了两个session,如果在程序的执行过程中遇到了异常,就有可能出现转账的错误。所以这样的写法是满足不了这种情况的。
sessionFaactory.openSession
每一次执行openSession 的时候会打开一个session ,效率比较低。
sessionFactory.getCurrentSession
原理
1. 从当前线程中(ThreadLocal)中,把session提取出来
2. 如果当前线程中没有session(第一步失败提取失败),则调用openSession方法创建一个session
3. 接着第二步,把session放入到threadlocal中。
4. 再执行第一步的步骤。
优点
不管有几个类完全松耦合,如果这几个类要用到同一个session,在运行的时候,如果这几个类在同一个线程下运行,利用threadlocal就能够保证是同一个session。
步骤
在Hibernate.cfg.xml文件中
|
|
在客户端
|
|
说明:
1. CRUD操作必须在事务的环境下运行(所以,上述的代码中,必须有session.beginTransaction())。
2. 事务提交,session自动关闭(如果手动再session.close()则会报出“session已经关闭的错误”)。
3. 这种方式强制把事务和session绑定在一起了。