hibernate mysql缓存机制_Hibernate 缓存机制

一、什么是缓存

缓存是内存中少部分数据的复制品,所以CPU到缓存中寻找数据时,也会出现找不到的情况(因为这些数据没有从内存复制到缓存中去),这时CPU还是会到内存中去找数据,这样系统的速率就慢下来了,不过CPU会把这些数据复制到缓存中去,以便下一次不要再到内存中去取。

二、Hibernate的一级缓存

(1)使用

Hibernate的一级缓存是默认开启的,当获取到一个Session对象,并执行save、update、saveOrUpdate、get方法时就会用到Hibernate一级缓存,当然也可以调用清除的放方法,Session为清除缓存提供了clear(清除所有的一级缓存)、evict(清除实例对象缓存)、refresh(重新查询数据并刷新缓存)。

例子:

//泛型查询实例

public E find(S s) {

//使用Spring 获取一个Session对象

Session session = getSession();

//执行查询操作

E bean = (E)session.get(entityClass, (Serializable) s);

//清除实例对象缓存

session.evict(bean);

//返回查询的对象

return bean;

}

(2)状态

Hibernate缓存状态分为瞬时状态、持久状态、脱管状态。

瞬时状态: 创建一个POJO,还未将对象数据保存到数据库时,Session中也没有当前POJO实例。

例子:

//创建一个POJO实例

Account account = new Account();

//给实例添加数据

account.setPhone("12345678931");

//这时实例并没有保存

持久状态: POJO对象被添加到Session缓存中,数据库也要有对应的数据。

例子:

public Integer saveStatus(Account entity) {

//获取Session对象

Session session = getSession();

//执行保存方法

Integer id = (Integer)session.save(entity);

//修改被持久化的POJO对象

entity.setState(4);

//返回对象ID

return id;

}

在上面的例子中,当保存事务还未提交,这时数据已经被持久化。这里会执行两条SQL,一条添加SQL,一条修改SQL(并没有调用修改方法为什么会执行修改SQL呢?因为Hibernate被持久化的POJO对象在被重新赋值时会触发更新操作。)

077339c532826fa040707450ba0db3b9.png

f644244380aabe698cc0958aaa5da7c2.png

脱管状态: 在缓存中已经被持久化的POJO对象,接着POJO对象执行了evict方法,这时POJO对象会从缓存中托管,但数据库中是有对应的数据。

例子:

public Integer saveStatus(Account entity) {

//获取Session对象

Session session = getSession();

//执行保存方法

Integer id = (Integer)session.save(entity);

//脱管当前POJO对象

session.evict(entity);

//修改被持久化的POJO对象

entity.setState(4);

//返回对象ID

return id;

}

调用evict方法将POJO对象传入,清除实例的持久化,修改POJO实例将不会在触发更新操作。

9cf3af861cd08b302fd7a57d4976ee23.png

(3)缓存绑定

Hibernate的一级缓存是绑定Session的,当获取到一个Session对象,在执行Sessinon里面的方法都能使用Hibernate默认提供的一级缓存,执行完成Session对象消亡即缓存数据也跟着消亡(一级缓存的数据是放在栈中)。

例子:

//通过id查询POJO实例

public E find(S s) {

Session session = getSession();

E bean = (E)session.get(entityClass, (Serializable) s);

return bean;

}

//调用三次上面的方法

accountService.find(1);

accountService.find(1);

accountService.find(1);

这里会执行三条查询SQL,这是因为里面获取的Session对象是线程安全的,彼此并没有任何关联(这也是为什么Spring不能用到Hibernate的一级缓存,其实不是Spring的问题)。

//通过id查询POJO实例

public E find(S s) {

Session session = getSession();

E bean = (E)session.get(entityClass, (Serializable) s);

E bean1 = (E)session.get(entityClass, (Serializable) s);

E bean2 = (E)session.get(entityClass, (Serializable) s);

return bean;

}

//调用上面的方法

accountService.find(1);

这里就算方法体里面执行三个查询操作,也只会执行一条查询SQL,因为使用的同一个Session对象,这就有使用到Hibernate的一级缓存。

二、Hibernate的二级缓存

(1)使用

Hibernate的二级缓存是默认关闭的(二级缓存的数据是放在堆中),如果需要开启二级缓存则需要额外的配置。

(2)配置

第一步:POJO对象设置

@Entity//POJO注解

@Table(name = "account")//对应的数据库表名称

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)//二级缓存配置,读写模式

public class Account {

...

}

第二步:配置Hibernate session工厂

update

org.hibernate.dialect.MySQLDialect

true

true

true

true

org.hibernate.cache.ehcache.EhCacheRegionFactory

classpath:applicationContext-ehcache.xml

com.test.entity

第三步:创建二级缓存配置文件

//maxElementsInMemory--缓存对象的最大数目

//eternal--对象是否永不过期,设置为true,过期时间则无效

//timeToldleSeconds--对象空闲多长时间未被使用就失效

//timeToLiveSeconds--对象被缓存的时间

//overflowToDisk--内存溢出时是否刷盘,如果为true则需要配置一个刷盘路径

//diskExpiryThreadIntervalSeconds--磁盘失效线程运行时间间隔

三、选择正确的方法

(1) Hibernatne查询分为两类:一类是得到单个对象,另一类是得到结果集。

单个对象:

get()方法和load()方法的区别在于对二级缓存的使用上。load()方法会使用二级缓存,而get()方法在一级缓存没有找到的情况下会直接查询数据库,不会去二级缓存中查找。在使用中,对使用了二级缓存的对象进行查询时最好使用load()方法,以充分利用二级缓存来提高检索的效率。

结果集对象:

list方法介绍

list()方法在执行时,是直接运行查询结果所需要的查询语句,而iterator()方法则是先执行得到对象ID的查询,然后再根据每个ID值去取得所要查询的对象。因此,对于list()方式的查询通常只会执行一个SQL语句,而对于iterator()方法的查询则可能需要执行N+1条SQL语句(N为结果集中的记录数)。

list()方法只能使用二级缓存中的查询缓存,而无法使用二级缓存对单个对象的缓存(但是会把查询出的对象放入二级缓存中)。所以,除非重复执行相同的查询操作,否则无法利用缓存的机制来提高查询的效率。

list()方法会一次获得所有的结果集对象,而且它会依据查询的结果初始化所有的结果集对象。这在结果集非常大的时候必然会占据非常多的内存,甚至会造成内存溢出情况的发生。

iterator方法介绍

iterator()方法只是可能执行N+1条数据,具体执行SQL语句的数量取决于缓存的情况以及对结果集的访问情况。

iterator()方法则可以充分利用二级缓存,在根据ID检索对象的时候会首先到缓存中查找,只有在找不到的情况下才会执行相应的查询语句。所以,缓存中对象的存在与否会影响到SQL语句的执行数量。

iterator()方法在执行时不会一次初始化所有的对象,而是根据对结果集的访问情况来初始化对象。因此在访问中可以控制缓存中对象的数量,以避免占用过多缓存,导致内存溢出情况的发生。使用iterator()方法的另外一个好处是,如果只需要结果集中的部分记录,那么没有被用到的结果对象根本不会被初始化。所以,对结果集的访问情况也是调用iterator()方法时执行数据库SQL语句多少的一个因素。

部分信息来自网络,欢迎大家指出错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值