Hibernate缓存如何实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate缓存如何实现相关的知识,希望对你有一定的参考价值。

事务提交后,一级缓存中的数据会被更新到数据库,如果二级缓存设置为读写,那么这份数据会同时更新到二级缓存
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。

Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。

Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存的两个特性:缓存的范围和缓存的并发访问策略。

持久化层的缓存的范围

缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。

1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。

2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。

3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。

对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。

持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。

持久化层的缓存的并发访问策略

当多个并发的事务同时访问持久化层的缓存的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。

在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下四种类型的并发访问策略,每一种策略对应一种事务隔离级别。

事务型:仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。

读写型:提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。

非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。

只读型:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。

事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。

什么样的数据适合存放到第二级缓存中?

1 很少被修改的数据

2 不是很重要的数据,允许出现偶尔并发的数据

3 不会被并发访问的数据

4 参考数据

不适合存放到第二级缓存的数据?

1 经常被修改的数据

2 财务数据,绝对不允许出现并发

3 与其他应用共享的数据。

Hibernate的二级缓存

如前所述,Hibernate提供了两级缓存,第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。

第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。

Hibernate的二级缓存策略的一般过程如下:

1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。

2) 把获得的所有数据对象根据ID放入到第二级缓存中。

3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

4) 删除、更新、增加数据的时候,同时更新缓存。

Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query缓存。

Hibernate的Query缓存策略的过程如下:

1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。

2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。

3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空.追问

我还想确定的是:在数据改变的时候,是先改变缓存中的数据,同时改变数据表中的数据.还是先改变数据表中的数据,同时更新缓存. 是否能够保证缓存中的数据和数据库中的数据保持同步,并且及时更新.

参考技术A 通过require、session实现一级和二级缓存。sessionfactory实现其他缓存

hibernate学习 六 Hibernate缓存

缓存

   如果在集群环境下使用Hibernate时,(集群有节点A ,节点B) 当请求,发往A节点,A在数据库中修改了一条记录,然后节点B的缓存中如何实时的更新节点A修改的新数据
         hibernate本身的一级缓存不能跨越进程, 需要第三方缓存的支持, Ehcache缓存就可以实现

Hibernate缓存:
  一级缓存:
       在同一个Session里面,第一次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索,没有再次发送select语句。
一个session不能取另一个session中的缓存。
二级缓存:
SessionFactory级别的缓存,可以跨越Session存在,可以被多个Session所共享。
(1)经常被访问

(2)改动不大

(3)数量有限

(4)不是很重要的数据,允许出现偶尔并发的数据。
用户的权限:用户的数量不大,权限不多,不会经常被改动,经常被访问。例如组织机构。

Hibernate查找对象如何应用缓存?
  当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;

  查不到,如果配置了二级缓存,那么从二级缓存中查;

  如果都查不到,再查询数据库,把结果按照ID放入到缓存, 删除、更新、增加数据的时候,同时更新缓存。

 

 

QBC(Query By Criteria) API提供了检索对象的另一种方式,:


Hibernate取部分字段?
  QBC是HQL更上层的封装,会查询所有字段。要想只使用部分字段,需要像写SQL一样写HQL。
  一种方案是:给实体类再加一个构造函数,构造函数只有必须的字段,这样就不会全查( String hql=”select new Employee(e.id,e.name_cn) from Employee e”; )
  另外一种是直接写SQL,得到的东西再组装成对象。Query query = getSession().createQuery(hql).setResultTransformer((Transformers.aliasToBean(clazz)));
  DetachedCriteria的投影方式可以取得部分字段。

hibernate多表联合查询?
  HQL:配置关系的话,可以不用join; 不配关系的话,HQL中写join;
  QBC的话,用createCriteria可以实现多表关联。Criteria repA=cri.createCriteria("repAward", CriteriaSpecification.LEFT_JOIN);
  Criteria works=cri.createCriteria("works", CriteriaSpecification.LEFT_JOIN);

HIbernate session 与 connection关系?

  • session与connection,是多对一关系,每个session都有一个与之对应的connection,一个connection不同时刻可以供多个session使用。
  • 多个session与一个connection绑定,底层操作数据库的时会进行同步。
  • 如果某个connection正在被某个session占用, open一个session,则创建一个新的connection与之对应。
  • 有连接池的情况下,session关闭后,connection不一定关闭, 还可以查询到应用占用的连接,若超过最大空闲时间,被连接池回收释放。
  • 有连接池的情况下,session使用完后不关闭,该connection被占用,若超过连接回收时间,也可被连接池回收释放。
  • 非连接池情况下,一个session占用一个connection,若不关闭,该connection无法释放。
  • 每个open的session都需要close。

 

连接池是多个端口吗?

  套接字是计算机网络中应用层和传输层之间的接口。如果应用程序需要使用网络功能,只需要调用套接字API即可。每个进程可以使用多个套接字,每个套接字都有一个标识符。对于TCP套接字,其标识符结构为:源IP,源端口,目的IP和目的端口。对于客户服务器架构的网络程序,服务器进程的端口是周知的,例如MySQL5543,而客户进程端口是随机分配的。也就是说,每个数据库连接对象,和数据库服务器通信都依赖于它自己的套接字,而这个套接字的端口号是各不相同的,尽管同属于一个进程。
























以上是关于Hibernate缓存如何实现的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate缓存总结

HIbernate学习笔记3 之 缓存和 对象的三种状态

具体解释Hibernate中的二级缓存

Hibernate

hibernate一级缓存

Hibernate一级缓存和二级缓存具体解释