redis作为hibernate的二级缓存

hibernate的二级缓存有好多,像ehcache。不过项目的缓存使用的是redis,而redis官方没有实现hibernate的二级缓存接口,只得自己实现。看看公司的高手如何做的吧。

先看配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- entityManagerFactory -->
     < bean id = "entityManagerFactory" class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
         depends-on = "cacheManagerFactory" >
         ...
         < property name = "jpaProperties" >
             < props >
                 ...
                 < prop key = "hibernate.cache.use_second_level_cache" >true</ prop >
                 <!-- <prop key="hibernate.cache.use_query_cache">true</prop> -->
                 < prop key = "hibernate.cache.region.factory_class" >xxx.xxx.framework.cache.hibernate.CacheRegionFactory</ prop >
                 ...
             </ props >
         </ property >
     </ bean >  
     
     <!-- cache -->
     < bean id = "cacheManager" class = "xxx.xxx.framework.cache.redis.RedisCacheManager" >
         < property name = "connectionFactory" ref = "redisConnectionFactory" />
         < property name = "namespace" value = "payment" />
     </ bean >
     
     < bean id = "cacheManagerFactory" class = "xxx.xxx.framework.cache.hibernate.CacheManagerFactory" >
         < property name = "cacheManager" ref = "cacheManager" />
     </ bean >

cacheManager是redis缓存的配置,二级缓存实现类CacheRegionFactory里面会用到它,但是hibernate缓存配置的只是配置实现类,没法注入CacheRegionFactory对象,所以这边多了个cacheManagerFactory,注意配置中的depends-on。它的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public final class CacheManagerFactory implements DisposableBean {
     private static CacheManager CACH_EMANAGER;
 
     public void setCacheManager(CacheManager cacheManager) {
         CACH_EMANAGER = cacheManager;
     }
 
     public static CacheManager getCacheManager() {
         return CACH_EMANAGER;
     }
 
     @Override
     public void destroy() throws Exception {
         CACH_EMANAGER = null ;
     }
}
它就是负责生成cacheManager。注意getCacheManager是静态方法。然后我们看redis二级缓存的实现类:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class CacheRegionFactory implements RegionFactory {
     private static final long serialVersionUID = -1557439471733872383L;
     private CacheManager cacheManager;
     private static final AtomicLong CURRENT = new AtomicLong();
     protected Settings settings;
 
     @Override
     public void start(Settings settings, Properties properties) throws CacheException {
         cacheManager = CacheManagerFactory.getCacheManager();
         this .settings = settings;
         Assert.notNull(cacheManager, "cacheManager is required,CacheManagerFactory must be init first" );
     }
 
     @Override
     public void stop() {
         cacheManager = null ;
     }
 
     @Override
     public boolean isMinimalPutsEnabledByDefault() {
         return true ;
     }
 
     @Override
     public AccessType getDefaultAccessType() {
         return AccessType.NONSTRICT_READ_WRITE;
     }
 
     @Override
     public long nextTimestamp() {
         return CURRENT.incrementAndGet();
     }
 
     @Override
     public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
         return new EntityRegionImpl(regionName, cacheManager.getCache(shortRegionName(regionName)), settings, properties, metadata);
     }
 
     @Override
     public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
         return new NaturalIdRegionImpl(regionName, cacheManager.getCache(shortRegionName(regionName)), settings, properties, metadata);
     }
 
     @Override
     public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
         return new CollectionRegionImpl(regionName, cacheManager.getCache(shortRegionName(regionName)), settings, properties, metadata);
     }
 
     @Override
     public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
         return new QueryResultsRegionImpl(regionName, cacheManager.getCache(shortRegionName(regionName)), settings, properties);
     }
 
     @Override
     public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
         return new TimestampsRegionImpl(regionName, cacheManager.getCache(shortRegionName(regionName)), settings, properties);
     }
 
     private static String shortRegionName(String regionName) {
         ...
     }
}
RegionFactory是hibernate的接口。在start里面通过调用CacheManagerFactory来获取redis的CacheManager。这里主要还是buildXX的几个方法,在这些方法里面通过  CacheManager和region获取cache,然后再生成hibernate需要的缓存对象


以buildEntityRegion为例,返回的对象EntityRegion是hibernate的接口,EntityRegionImpl怎是我们的实现。先看看它的实现:

?
1
2
3
4
5
6
7
8
9
10
11
public class EntityRegionImpl extends AbstractTransactionalDataRegion implements EntityRegion {
 
     public EntityRegionImpl(String regionName, Cache cache, Settings settings, Properties properties, CacheDataDescription metadata) {
         super (regionName,cache, settings, properties, metadata);
     }
 
     @Override
     public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
         return new EntityRegionAccessStrategyImpl( this , settings);
     }
}
这边可以分两部分看了一个是它的父类AbstractTransactionalDataRegion,另外一个是由EntityRegion继承而来的buildAccessStrategy(Hibernate EntityRegion的接口实现)。

先看它的父类,父类实现了hibernate的TansactionalDateRegion:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AbstractTransactionalDataRegion extends AbstractRegion implements TransactionalDataRegion {
     private final CacheDataDescription metadata;
 
     public AbstractTransactionalDataRegion(String regionName, Cache cache, Settings settings, Properties properties, CacheDataDescription metadata) {
         super (regionName, cache, settings, properties);
         this .metadata = metadata;
     }
 
     @Override
     public boolean isTransactionAware() {
         return false ;
     }
 
     @Override
     public CacheDataDescription getCacheDataDescription() {
         return metadata;
     }
}
isTransactionAware是表示是否支持jta事务。然后再看它的父类AbstractRegion:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class AbstractRegion implements Region {
     private static final AtomicLong CURRENT = new AtomicLong();
     private String regionName;
     protected final Cache cache;
     protected final Properties properties;
     protected final Settings settings;
     protected final KeyGenerator keyGenerator = DefaultKeyGenerator.INSTANCE;
 
     public AbstractRegion(String regionName, Cache cache, Settings settings, Properties properties) {
         this .regionName = regionName;
         this .cache = cache;
         this .settings = settings;
         this .properties = properties;
     }
 
     @Override
     public String getName() {
         return regionName;
     }
 
     @Override
     public void destroy() throws CacheException {
     }
 
     @Override
     public boolean contains(Object key) {
         return cache.exists(key);
     }
 
     @Override
     public long getSizeInMemory() {
         return - 1 ;
     }
 
     @Override
     public long getElementCountInMemory() {
         return cache.getStatistics().getSize();
     }
 
     @Override
     public long getElementCountOnDisk() {
         return - 1 ;
     }
 
     @Override
     public Map toMap() {
         return Collections.EMPTY_MAP;
     }
 
     @Override
     public long nextTimestamp() {
         return CURRENT.incrementAndGet();
     }
 
     @Override
     public int getTimeout() {
         return 300 ;
     }
 
     public Object get(Object key) throws CacheException {
         try {
             return postGet(cache.get(toKey(key)));
         } catch (Throwable e) {
             throw new CacheException(e);
         }
     }
 
     public void put(Object key, Object value) throws CacheException {
         try {
             cache.put(toKey(key), value);
         } catch (Exception e) {
             throw new CacheException(e);
         }
     }
 
     public void evict(Object key) throws CacheException {
         try {
             cache.evict(toKey(key));
         } catch (Exception e) {
             throw new CacheException(e);
         }
     }
 
     public void evictAll() throws CacheException {
         try {
             cache.clear();
         } catch (Exception e) {
             throw new CacheException(e);
         }
     }
 
     private Object toKey(Object key) {
         if (key instanceof CacheKey) {
             key = ((CacheKey) key).getKey();
         }
         return keyGenerator.generate(key);
     }
......
这里实现了hibernate region的一些接口,另外一些对于缓存的一些操作方法如:put\get\evict等也做了实现。

现在我们回过头看看EntityRegionImpl里面的EntityRegionAccessStrategyImpl实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class EntityRegionAccessStrategyImpl extends AbstractAccessStrategy<EntityRegionImpl> implements EntityRegionAccessStrategy {
 
 
    public EntityRegionAccessStrategyImpl(EntityRegionImpl region, Settings settings) {
        super (region, settings);
    }
 
 
    @Override
    public EntityRegion getRegion() {
        return region;
    }
}
它也实现了hibernate的接口:EntityRegionAccessStrategy,字面意思就是缓存的访问策略。

先看看hibernate的这个接口的定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public interface EntityRegionAccessStrategy extends RegionAccessStrategy{
 
     /**
      * Get the wrapped entity cache region
      *
      * @return The underlying region
      */
     public EntityRegion getRegion();
 
     /**
      * Called after an item has been inserted (before the transaction completes),
      * instead of calling evict().
      * This method is used by "synchronous" concurrency strategies.
      *
      * @param key The item key
      * @param value The item
      * @param version The item's version value
      * @return Were the contents of the cache actual changed by this operation?
      * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
      */
     public boolean insert(Object key, Object value, Object version) throws CacheException;
 
     /**
      * Called after an item has been inserted (after the transaction completes),
      * instead of calling release().
      * This method is used by "asynchronous" concurrency strategies.
      *
      * @param key The item key
      * @param value The item
      * @param version The item's version value
      * @return Were the contents of the cache actual changed by this operation?
      * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
      */
     public boolean afterInsert(Object key, Object value, Object version) throws CacheException;
 
     /**
      * Called after an item has been updated (before the transaction completes),
      * instead of calling evict(). This method is used by "synchronous" concurrency
      * strategies.
      *
      * @param key The item key
      * @param value The item
      * @param currentVersion The item's current version value
      * @param previousVersion The item's previous version value
      * @return Were the contents of the cache actual changed by this operation?
      * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
      */
     public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException;
 
     /**
      * Called after an item has been updated (after the transaction completes),
      * instead of calling release().  This method is used by "asynchronous"
      * concurrency strategies.
      *
      * @param key The item key
      * @param value The item
      * @param currentVersion The item's current version value
      * @param previousVersion The item's previous version value
      * @param lock The lock previously obtained from {@link #lockItem}
      * @return Were the contents of the cache actual changed by this operation?
      * @throws CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region}
      */
     public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException;
}
它的父接口里面还有一些其他的接口如get,remove等可以直接看看源码注释上面都写了。

我们的实现类同时有个父类AbstractAccessStrategy<EntityRegionImpl>,很多EntityRegionAccessStrategy因为都是公用的所以在AbstractAccessStrategy中实现了。看代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public abstract class AbstractAccessStrategy<T extends AbstractTransactionalDataRegion> {
     protected final T region;
     protected final Settings settings;
 
     public AbstractAccessStrategy(T region, Settings settings) {
         this .region = region;
         this .settings = settings;
     }
 
     public boolean insert(Object key, Object value) throws CacheException {
         return insert(key, value, null );
     }
 
     public boolean insert(Object key, Object value, Object version) throws CacheException {
         return false ;
     }
 
     public boolean afterInsert(Object key, Object value) throws CacheException {
         return afterInsert(key, value, null );
     }
 
     public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
         return false ;
     }
 
     public boolean update(Object key, Object value) throws CacheException {
         return update(key, value, null , null );
     }
 
     public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
         remove(key);
         return false ;
     }
 
     public boolean afterUpdate(Object key, Object value, SoftLock lock) throws CacheException {
         return afterUpdate(key, value, null , null , lock);
     }
 
     public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException {
         unlockItem(key, lock);
         return false ;
     }
 
     public Object get(Object key, long txTimestamp) throws CacheException {
         return region.get(key);
     }
 
     public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
         return putFromLoad(key, value, txTimestamp, version, settings.isMinimalPutsEnabled());
     }
 
     public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
         if (minimalPutOverride && region.contains(key)) {
             return false ;
         } else {
             region.put(key, value);
             return true ;
         }
     }
 
     public SoftLock lockItem(Object key, Object version) throws CacheException {
         return null ;
     }
 
     public SoftLock lockRegion() throws CacheException {
         return null ;
     }
 
     public void unlockItem(Object key, SoftLock lock) throws CacheException {
         region.evict(key);
     }
 
     public void unlockRegion(SoftLock lock) throws CacheException {
         region.evictAll();
     }
 
     public void remove(Object key) throws CacheException {
         region.evict(key);
     }
 
     public void removeAll() throws CacheException {
         region.evictAll();
     }
 
     public void evict(Object key) throws CacheException {
         region.evict(key);
     }
 
     public void evictAll() throws CacheException {
         region.evictAll();
     }
}

上面的方法有些怪异如insert方法,里面就直接返回false了,问了高手,他说参考ehcache的实现。看了下ehcache的源码它上面写了:A no-op since this is an asynchronous cache access strategy。这个和hibernate接口定义的insert注释有点出入:

?
1
2
3
* Called after an item has been inserted (before the transaction completes),
      * instead of calling evict().
      * This method is used by "synchronous" concurrency strategies.
总之这块不是很理解。

转http://my.oschina.net/yybear/blog/102216

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值