`
caoxiaohucxh
  • 浏览: 941 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Hibernate cache 缓存

阅读更多
二、hibernate二级缓存避免查询Cache需要先获得db连接
hibernate自身管理一级缓存,如果需要使用二级缓存,则要自己来实现相应的代码,这个实现起来并不复杂只需要实现
hibernate提供的相应的接口即可。我们在项目中选用了最为通用的memcached,具体配置如下:
在spring中配置hibernateProperties是增加一项配置
Java代码
<prop key="hibernate.cache.provider_class">com.*.frame.cache.memcached.MemcachedCacheProvider</prop> 

<prop key="hibernate.cache.provider_class">com.*.frame.cache.memcached.MemcachedCacheProvider</prop>
MemcachedCacheProvider需要实现hibernate提供的CacheProvider接口:
Java代码
public class MemcachedCacheProvider implements CacheProvider {  
    public final static String DEFAULT_REGION_NAME="____DEFAULT_CACHE_REGION";  
 
    public void start(Properties props) throws CacheException {  
        CachePoolManager pool = CachePoolManager.getInstance();  
    }  
 
    public Cache buildCache(String name, Properties props) throws CacheException {  
        if(StringUtils.isEmpty(name))  
            name = DEFAULT_REGION_NAME;  
        //项目中已经实现并且再用的的Memacached工具类  
        MemCache mCache = (MemCache)CachePoolManager.getInstance().getCache(name);  
        return mCache;  
    }  
 
    public void stop() {  
//      CachePoolManager.getInstance().finalize();  
    }  
 
    public boolean isMinimalPutsEnabledByDefault() {  
        return false;  
    }  
 
    public long nextTimestamp() {  
        return Timestamper.next();  
    }  


public class MemcachedCacheProvider implements CacheProvider {
public final static String DEFAULT_REGION_NAME="____DEFAULT_CACHE_REGION";

public void start(Properties props) throws CacheException {
CachePoolManager pool = CachePoolManager.getInstance();
}

public Cache buildCache(String name, Properties props) throws CacheException {
if(StringUtils.isEmpty(name))
name = DEFAULT_REGION_NAME;
//项目中已经实现并且再用的的Memacached工具类
MemCache mCache = (MemCache)CachePoolManager.getInstance().getCache(name);
return mCache;
}

public void stop() {
// CachePoolManager.getInstance().finalize();
}

public boolean isMinimalPutsEnabledByDefault() {
return false;
}

public long nextTimestamp() {
return Timestamper.next();
}
}
Memcached实体类也要实现hibernate提供的Cache接口:
Java代码
public class MemCache implements Cache {  
    private static final Log log = LogFactory.getLog(MemCache.class);  
    private static final int SIXTY_THOUSAND_MS = 60000;  
    private MemCachedClient mc;  
    private int secondToLive;  
    private String cache_name;  
    private String poolName;  
    public MemCache(String poolName, String regionName, int secondToLive){  
*****部分代码省略  
/** 
     * Get an item from the cache 
     * @param key 
     * @return the cached object or <tt>null</tt> 
     * @throws CacheException 
     */ 
    public Object read(Object key) throws CacheException;  
    /** 
     * Get an item from the cache, nontransactionally 
     * @param key 
     * @return the cached object or <tt>null</tt> 
     * @throws CacheException 
     */ 
    public Object get(Object key) throws CacheException;  
    /** 
     * Add an item to the cache, nontransactionally, with 
     * failfast semantics 
     * @param key 
     * @param value 
     * @throws CacheException 
     */ 
    public void put(Object key, Object value) throws CacheException;  
    /** 
     * Add an item to the cache 
     * @param key 
     * @param value 
     * @throws CacheException 
     */ 
    public void update(Object key, Object value) throws CacheException;  
    /** 
     * Remove an item from the cache 
     */ 
    public void remove(Object key) throws CacheException;  
    /** 
     * Clear the cache 
     */ 
    public void clear() throws CacheException;  
    /** 
     * Clean up 
     */ 
    public void destroy() throws CacheException;  
    /** 
     * If this is a clustered cache, lock the item 
     */ 
    public void lock(Object key) throws CacheException;  
    /** 
     * If this is a clustered cache, unlock the item 
     */ 
    public void unlock(Object key) throws CacheException;  
    /** 
     * Generate a timestamp 
     */ 
    public long nextTimestamp();  
    /** 
     * Get a reasonable "lock timeout" 
     */ 
    public int getTimeout();  
      
    /** 
     * Get the name of the cache region 
     */ 
    public String getRegionName();  
 
    /** 
     * The number of bytes is this cache region currently consuming in memory. 
     * 
     * @return The number of bytes consumed by this region; -1 if unknown or 
     * unsupported. 
     */ 
    public long getSizeInMemory();  
 
    /** 
     * The count of entries currently contained in the regions in-memory store. 
     * 
     * @return The count of entries in memory; -1 if unknown or unsupported. 
     */ 
    public long getElementCountInMemory();  
 
    /** 
     * The count of entries currently contained in the regions disk store. 
     * 
     * @return The count of entries on disk; -1 if unknown or unsupported. 
     */ 
    public long getElementCountOnDisk();  
      
    /** 
     * optional operation 
     */ 
    public Map toMap();  


public class MemCache implements Cache {
private static final Log log = LogFactory.getLog(MemCache.class);
private static final int SIXTY_THOUSAND_MS = 60000;
private MemCachedClient mc;
private int secondToLive;
private String cache_name;
private String poolName;
public MemCache(String poolName, String regionName, int secondToLive){
*****部分代码省略
/**
* Get an item from the cache
* @param key
* @return the cached object or <tt>null</tt>
* @throws CacheException
*/
public Object read(Object key) throws CacheException;
/**
* Get an item from the cache, nontransactionally
* @param key
* @return the cached object or <tt>null</tt>
* @throws CacheException
*/
public Object get(Object key) throws CacheException;
/**
* Add an item to the cache, nontransactionally, with
* failfast semantics
* @param key
* @param value
* @throws CacheException
*/
public void put(Object key, Object value) throws CacheException;
/**
* Add an item to the cache
* @param key
* @param value
* @throws CacheException
*/
public void update(Object key, Object value) throws CacheException;
/**
* Remove an item from the cache
*/
public void remove(Object key) throws CacheException;
/**
* Clear the cache
*/
public void clear() throws CacheException;
/**
* Clean up
*/
public void destroy() throws CacheException;
/**
* If this is a clustered cache, lock the item
*/
public void lock(Object key) throws CacheException;
/**
* If this is a clustered cache, unlock the item
*/
public void unlock(Object key) throws CacheException;
/**
* Generate a timestamp
*/
public long nextTimestamp();
/**
* Get a reasonable "lock timeout"
*/
public int getTimeout();

/**
* Get the name of the cache region
*/
public String getRegionName();

/**
* The number of bytes is this cache region currently consuming in memory.
*
* @return The number of bytes consumed by this region; -1 if unknown or
* unsupported.
*/
public long getSizeInMemory();

/**
* The count of entries currently contained in the regions in-memory store.
*
* @return The count of entries in memory; -1 if unknown or unsupported.
*/
public long getElementCountInMemory();

/**
* The count of entries currently contained in the regions disk store.
*
* @return The count of entries on disk; -1 if unknown or unsupported.
*/
public long getElementCountOnDisk();

/**
* optional operation
*/
public Map toMap();
}

至于Memcached实体类里的MemCachedClient 的实现,可以更加网上流传的不同版本进行修改和优化。
第四步,在需要使用缓存的类对应的映射文件中加入缓存策略的配置,如:<cache usage="nonstrict-read-write" />,还有其他选项read-only,read-write,transactional等。
    大功告成,打开hibernate.show_sql重启应用。刷新列表,第一次看到一大堆的sql语句,再次刷新只出现两条,第三次还是两条,我们配置的二级缓存生效了。
做一次压力测试,具体压力测试的报告丢失没法拿出具体的数字。当时大概的现象是,应用响应比较慢,数据库连接几乎耗尽,队列等待情况严重。
我们知道hibernate从cache中查找的时候,先从数据库拿到相应的id然后根据id去cache中取到相应的数据后返回。压力测试只是模拟的同一个请求,意味着每次要查询的东西必然已经存在于cache里了,为什么dbConnection会不够用呢?
    一个分析系统问题的利器该出场了——log4j。顺便说句,java开发不可避免的采用框架,当然有人坚持原生态,这个另说。几乎所有的框架都采用log4j输出日志,仔细分析日志不难发现很多问题。首先,设置日志级别Debug,其次去掉一些无用的信息,比如初始化、加载配置文件等等。准备工作完成后,咱们模拟用户的行为进行一次操作。这个时候输出的日志就会记录一个请求执行的所有的过滤器,拦截器,方法等堆栈信息。   
Java代码
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - begin  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - opening JDBC connection  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - current autocommit status: true 
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - disabling autocommit  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.cache.NonstrictReadWriteCache - Cache lookup: com.**#3827849 
[DEBUG] 2010-07-28 11:28:31 com.**.frame.cache.memcached.MemCache - key: com.**#3827849 
[DEBUG] 2010-07-28 11:28:31 com.**.frame.cache.memcached.SockIOPool$SockIO - ++++ marking socket (Socket[addr=/127.0.0.1,port=11211,localport=56135]) as closed and available to return to avail pool  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.cache.NonstrictReadWriteCache - Cache hit//已经命中  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.engine.StatefulPersistenceContext - initializing non-lazy collections  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - commit  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - re-enabling autocommit  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - committed JDBC Connection  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection  
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - releasing JDBC connection 

[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - begin
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - opening JDBC connection
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - current autocommit status: true
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - disabling autocommit
[DEBUG] 2010-07-28 11:28:31 org.hibernate.cache.NonstrictReadWriteCache - Cache lookup: com.**#3827849
[DEBUG] 2010-07-28 11:28:31 com.**.frame.cache.memcached.MemCache - key: com.**#3827849
[DEBUG] 2010-07-28 11:28:31 com.**.frame.cache.memcached.SockIOPool$SockIO - ++++ marking socket (Socket[addr=/127.0.0.1,port=11211,localport=56135]) as closed and available to return to avail pool
[DEBUG] 2010-07-28 11:28:31 org.hibernate.cache.NonstrictReadWriteCache - Cache hit//已经命中
[DEBUG] 2010-07-28 11:28:31 org.hibernate.engine.StatefulPersistenceContext - initializing non-lazy collections
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - commit
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
[DEBUG] 2010-07-28 11:28:31 org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
[DEBUG] 2010-07-28 11:28:31 org.hibernate.jdbc.ConnectionManager - releasing JDBC connection
    通过对log4j日志分析发现,hibernate每次先get一个jdbcConnection,从数据库查询出一堆id,然后去cache查找对象。如果数据在cache中存在则取出,并提交事务释放连接;如果cache中没有,则查询数据库并将结果保存的cache中,提交事务释放连接。问题来了:既然cache中有想要查询的数据,为什么要先获取一个数据库连接、开启事务然后再去缓存中查找呢?假如所有用户查询的内容在cache中都存在,每个请求都要获取一个jdbc连接才能去查找cache,那么系统瓶颈必然会出现的连接池的连接数上。这也就不难解释为什么做压力测试时出现数据库连接耗尽的情况。由此我们得出一个结论:hibernate需要维持着数据库连接去cache中查找数据,只是减少了对数据库的查找次数,并没有减少应用的db连接数。
    如何解决这个问题?理想的情况是,cache中有的直接去cache中查找,cache中没有的去db查询然后放入cache中。将代码做些修改,只从数据库中查到id,根据id去cache中查找相应的数据,cache中没有的数据则调用hibernate的查询方法。由于之前我们已经配置了缓存策略,所以hibernate查询到相应的数据后会自动放入cache中。这样一来,当第一次请求的时候先去db中拿到id,然后把所有的数据装入到cache中,第二次请求时先去查询出id,然后去cache中查找数据。以后的每次操作,只有查询id时取得数据库连接,结果集返回连接就被释放掉。这样避免了hibernate需要维持着db连接去查询cache的问题。
    在从cache中获取数据的地方遇到了些麻烦,hibernate写入cache中的对象,我们能写代码取到但是无法进行解析。相关的资料介绍,hibernate对存入二级缓存的东西默认进行了封装且不提供对外的接口进行数据的解析,至于原因和封装成什么类型这里不再赘述。我们可以通过配置改变hibernate保存的对象在cache中的数据结构。具体办法:在配置hibernateProperties是增加一项配置Java代码
<prop key="hibernate.cache.use_structured_entries">true</prop> 

<prop key="hibernate.cache.use_structured_entries">true</prop>,这样存入二级缓存的对象是一个保存属性名和属性值的map,解析map即可得到相应数据。
    虽然这样一来,针对二级缓存的使用有些侵入性,但是可以保证了hibernate对二级缓存的读取不会像默认的那样需要保持着一个数据库连接。
分享到:
评论

相关推荐

    Hibernate 高级配置

    Hibernate高级配置 1. Hibernate与触发器协同工作 1)、触发器使session的缓存中的数据与数据库中的数据不一致 2)、session的update()方法...7. hibernate cache 缓存 8. hibernate缓存方案 9. Hibernate二级缓存配置

    7:Hibernate查询缓存及实现.PPT

    7:Hibernate查询缓存Query Cache及实现

    hibernate4.0使用二级缓存jar包

    &lt;property name="hibernate.cache.region.factory_class"&gt;org.hibernate.cache.ehcache.EhCacheRegionFactory 3.3配置如下: &lt;property name="hibernate.cache.use_second_level_cache"&gt;true &lt;property name="cache...

    Hibernate 使用缓存时,数据同步问题

    Hibernate 使用缓存时,数据同步问题

    Hibernate的cache缓存解析

    基本的缓存原理,存在的问题,动态表相关.。。。

    hibernate二级缓存

    Hibernate二级缓存 在一个数据库系统中,如果缓存设置的... hibernate.cache.use_query_cache必须配置,如果想缓存使用findall()、list()、Iterator()、createCriteria()、 createQuery()等方法获得的数据结果集。

    hibernate_cache_level_1

    学习hibernate_cache_level二级缓存项目

    hibernate 3中的缓存小结

    hibernate 3中的缓存小结 2.2. 一级缓存的管理: 当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存中还不存在...

    Spring集成的Hibernate配置二级缓存

    传播智客,为Spring集成的Hibernate配置二级缓存、cache.xml

    Hibernate 缓存 实例

    Hibernate cache Demo ,手把手教程

    hibernate二级缓存(包括注解方式)

    NULL 博文链接:https://zhaoshijie.iteye.com/blog/998230

    Hibernate_二级缓存总结

    一、缓存简介 Cache In Hibernate HIBERNATE 中的 CACHE 有两级 . 一级是在 Session 范围内的 CACHE . 即每个 Session 有自己的一个 CACHE, 当前操作的对象都会被保留在 CACHE 中 . 但是 Session 关闭后这个 CACHE...

    深入剖析hibernate的n+1问题和缓存问题

    深入理解hibernate的缓存问题和配置,提高使用hibernate的效率

    Hibernate的缓存机制

    缓存(Cache )是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据...

    hibernate二级缓存使用范例

    Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程...

    hibernate一级和二级缓存配置与详解

    主要讲解hibernate缓存的配置和和使用方法,以及一级缓存和二级缓存的定义和区别,和查询缓存的使用

    最新二级缓存memcached,支持hibernate4

    解决目前memcached不支持hibernate4的缺陷,hibernate配置&lt;property name="hibernate.cache.region.factory_class"&gt;com.googlecode.hibernate.memcached.MemcachedRegionFactory&lt;/property&gt;

    Hibernate Jboss cache

    基于Jboss Cache的hibernate二级缓存机制

    hibernate二级缓存 SSH

    文件中是一个简单的SSH集成,带hibernate二级缓存,有点烂,但是初学者还是可以看看数据库是sqlserver,代码齐全,有sql脚本,部署到tomcat就可以跑

    grails-redis-hibernate-cache:Grails 与 Redis 的集成作为 Hibernate 二级缓存的后端

    Grails Redis Hibernate 二级缓存 这个插件简化了 Grails Hibernate 2nd Level 缓存和 Redis 之间的集成。 安装 要安装,您需要将插件添加到 BuildConfig.groovy 中 compile " :redis-hibernate-cache:1.0 " 还有这...

Global site tag (gtag.js) - Google Analytics