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
;
}
}
|
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) {
...
}
}
|
以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);
}
}
|
先看它的父类,父类实现了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;
}
}
|
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);
}
......
|
现在我们回过头看看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的这个接口的定义:
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;
}
|
我们的实现类同时有个父类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