Mybatis整合redis实现缓存
概述
Mybatis默认缓存是PerpetualCache,它实现了Cache接口。Mybatis为了方便我们扩展缓存定义了一个Cache接口,因此,我们只需要参考源码自己使用redis实现Cache接口,即可达到Mybatis整合redis管理缓存的目的。
开始
本文介绍在spring-mvc的项目中,如何实现使用redis作为Mybatis的二级缓存。重点是实现Cache接口,而如何引入redis有多种方式,本文使用其中一种。
环境
- jdk:1.7
- redis:2.8.12
- spring:4.1.1.RELEASE
新建redis.properties文件
用于记录redis的基本信息
1# ====================================================
2# redis settings
3# ====================================================
4
5redis.host=127.0.0.1
6redis.port=6379
7redis.pass=
8redis.maxIdle=300
9redis.maxActive=600
10redis.maxWait=1000
11redis.testOnBorrow=false
新建RedisConfig.java类
用于获取redis配置信息
1public class RedisConfig {
2
3 private static String host;
4 private static String port;
5 private static String pass;
6 private static String maxIdle;
7 private static String maxActive;
8 private static String maxWait;
9 private static String testOnBorrow;
10
11 public RedisConfig(String host, String port, String pass, String maxIdle,
12 String maxActive, String maxWait, String testOnBorrow) {
13 super();
14 RedisConfig.host = host;
15 RedisConfig.port = port;
16 RedisConfig.pass = pass;
17 RedisConfig.maxIdle = maxIdle;
18 RedisConfig.maxActive = maxActive;
19 RedisConfig.maxWait = maxWait;
20 RedisConfig.testOnBorrow = testOnBorrow;
21 }
22
23 public static String getHost() {
24 return host;
25 }
26
27 public static String getPort() {
28 return port;
29 }
30
31 public static String getPass() {
32 return pass;
33 }
34
35 public static String getMaxIdle() {
36 return maxIdle;
37 }
38
39 public static String getMaxActive() {
40 return maxActive;
41 }
42
43 public static String getMaxWait() {
44 return maxWait;
45 }
46
47 public static String getTestOnBorrow() {
48 return testOnBorrow;
49 }
50
51 public void setHost(String host) {
52 RedisConfig.host = host;
53 }
54
55 public void setPort(String port) {
56 RedisConfig.port = port;
57 }
58
59 public void setPass(String pass) {
60 RedisConfig.pass = pass;
61 }
62
63 public void setMaxIdle(String maxIdle) {
64 RedisConfig.maxIdle = maxIdle;
65 }
66
67 public void setMaxActive(String maxActive) {
68 RedisConfig.maxActive = maxActive;
69 }
70
71 public void setMaxWait(String maxWait) {
72 RedisConfig.maxWait = maxWait;
73 }
74
75 public void setTestOnBorrow(String testOnBorrow) {
76 RedisConfig.testOnBorrow = testOnBorrow;
77 }
78
79}
spring配置文件中构造RedisConfig
1 <context:property-placeholder
2 location="classpath:redis.properties"
3 ignore-unresolvable="true" ignore-resource-not-found="true" />
4
5 <bean id="redisConfig" class="cn.essa.component.privilege.util.RedisConfig">
6 <constructor-arg index="0">
7 <value>${redis.host}</value>
8 </constructor-arg>
9 <constructor-arg index="1">
10 <value>${redis.port}</value>
11 </constructor-arg>
12 <constructor-arg index="2">
13 <value>${redis.pass}</value>
14 </constructor-arg>
15 <constructor-arg index="3">
16 <value>${redis.maxIdle}</value>
17 </constructor-arg>
18 <constructor-arg index="4">
19 <value>${redis.maxActive}</value>
20 </constructor-arg>
21 <constructor-arg index="5">
22 <value>${redis.maxWait}</value>
23 </constructor-arg>
24 <constructor-arg index="6">
25 <value>${redis.testOnBorrow}</value>
26 </constructor-arg>
27 </bean>
如此即可在普通类中使用RedisConfig,得到redis配置信息
新建RedisCache.java类
该类实现了org.apache.ibatis.cache.Cache接口
1/**
2 * @ClassName: RedisCache
3 * @Description: 使用第三方缓存服务器redis,处理二级缓存
4 * @author cipher
5 *
6 */
7public class RedisCache implements Cache {
8 private static final Log LOG = LogFactory.getLog(RedisCache.class);
9 /** The ReadWriteLock. */
10 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
11
12 private String id;
13
14 public RedisCache(final String id) {
15 if (id == null) {
16 throw new IllegalArgumentException("必须传入ID");
17 }
18 LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>MybatisRedisCache:id=" + id);
19 this.id = id;
20 }
21
22 @Override
23 public String getId() {
24 return this.id;
25 }
26
27 @Override
28 public int getSize() {
29 Jedis jedis = null;
30 JedisPool jedisPool = null;
31 int result = 0;
32 boolean borrowOrOprSuccess = true;
33 try {
34 jedis = CachePool.getInstance().getJedis();
35 jedisPool = CachePool.getInstance().getJedisPool();
36 result = Integer.valueOf(jedis.dbSize().toString());
37 } catch (JedisConnectionException e) {
38 LOG.error(e);
39 borrowOrOprSuccess = false;
40 if (jedis != null) {
41 jedisPool.returnBrokenResource(jedis);
42 }
43 } finally {
44 if (borrowOrOprSuccess) {
45 jedisPool.returnResource(jedis);
46 }
47 }
48 return result;
49
50 }
51
52 @Override
53 public void putObject(Object key, Object value) {
54 if (LOG.isDebugEnabled()) {
55 LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>putObject:"
56 + key.hashCode() + "=" + value);
57 }
58 if (LOG.isInfoEnabled()) {
59 LOG.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>put to redis sql :"
60 + key.toString());
61 }
62 Jedis jedis = null;
63 JedisPool jedisPool = null;
64 boolean borrowOrOprSuccess = true;
65 try {
66 jedis = CachePool.getInstance().getJedis();
67 jedisPool = CachePool.getInstance().getJedisPool();
68 jedis.set(SerializeUtil.serialize(key.hashCode()),
69 SerializeUtil.serialize(value));
70 } catch (JedisConnectionException e) {
71 LOG.error(e);
72 borrowOrOprSuccess = false;
73 if (jedis != null) {
74 jedisPool.returnBrokenResource(jedis);
75 }
76 } finally {
77 if (borrowOrOprSuccess) {
78 jedisPool.returnResource(jedis);
79 }
80 }
81
82 }
83
84 @Override
85 public Object getObject(Object key) {
86 Jedis jedis = null;
87 JedisPool jedisPool = null;
88 Object value = null;
89 boolean borrowOrOprSuccess = true;
90 try {
91 jedis = CachePool.getInstance().getJedis();
92 jedisPool = CachePool.getInstance().getJedisPool();
93 value = SerializeUtil.unserialize(jedis.get(SerializeUtil
94 .serialize(key.hashCode())));
95 } catch (JedisConnectionException e) {
96 LOG.error(e);
97 borrowOrOprSuccess = false;
98 if (jedis != null) {
99 jedisPool.returnBrokenResource(jedis);
100 }
101 } finally {
102 if (borrowOrOprSuccess) {
103 jedisPool.returnResource(jedis);
104 }
105 }
106 if (LOG.isDebugEnabled()) {
107 LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>getObject:"
108 + key.hashCode() + "=" + value);
109 }
110 return value;
111 }
112
113 @Override
114 public Object removeObject(Object key) {
115 Jedis jedis = null;
116 JedisPool jedisPool = null;
117 Object value = null;
118 boolean borrowOrOprSuccess = true;
119 try {
120 jedis = CachePool.getInstance().getJedis();
121 jedisPool = CachePool.getInstance().getJedisPool();
122 value = jedis.expire(SerializeUtil.serialize(key.hashCode()), 0);
123 } catch (JedisConnectionException e) {
124 LOG.error(e);
125 borrowOrOprSuccess = false;
126 if (jedis != null) {
127 jedisPool.returnBrokenResource(jedis);
128 }
129 } finally {
130 if (borrowOrOprSuccess) {
131 jedisPool.returnResource(jedis);
132 }
133 }
134 if (LOG.isDebugEnabled()) {
135 LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>removeObject:"
136 + key.hashCode() + "=" + value);
137 }
138 return value;
139 }
140
141 @Override
142 public void clear() {
143 Jedis jedis = null;
144 JedisPool jedisPool = null;
145 boolean borrowOrOprSuccess = true;
146 try {
147 jedis = CachePool.getInstance().getJedis();
148 jedisPool = CachePool.getInstance().getJedisPool();
149 jedis.flushDB();
150 jedis.flushAll();
151 } catch (JedisConnectionException e) {
152 LOG.error(e);
153 borrowOrOprSuccess = false;
154 if (jedis != null) {
155 jedisPool.returnBrokenResource(jedis);
156 }
157 } finally {
158 if (borrowOrOprSuccess) {
159 jedisPool.returnResource(jedis);
160 }
161 }
162 }
163
164 @Override
165 public ReadWriteLock getReadWriteLock() {
166 return readWriteLock;
167 }
168
169 /**
170 *
171 * @ClassName: CachePool
172 * @Description: 单例Cache池
173 *
174 */
175 public static class CachePool {
176 JedisPool pool;
177 private static final CachePool CACHEPOOL = new CachePool();
178
179 public static CachePool getInstance() {
180 return CACHEPOOL;
181 }
182
183 private CachePool() {
184 try {
185 int maxIdle = Integer
186 .valueOf(RedisConfig.getMaxIdle());
187 long maxWait = Long.valueOf(RedisConfig.getMaxWait());
188 int maxActive = Integer.valueOf(RedisConfig.getMaxActive());
189 String redisHost = RedisConfig.getHost();
190 int redisPort = Integer.valueOf(RedisConfig.getPort());
191 JedisPoolConfig config = new JedisPoolConfig();
192 config.setMaxIdle(maxIdle);
193 config.setMaxWait(maxWait);
194 config.setMaxActive(maxActive);
195 config.setTestOnBorrow(false);
196 pool = new JedisPool(config, redisHost, redisPort);
197 } catch (Exception e) {
198 LOG.error(e);
199 throw new RuntimeException("初始化连接池错误");
200 }
201 }
202
203 public Jedis getJedis() {
204 Jedis jedis = null;
205 boolean borrowOrOprSuccess = true;
206 try {
207 jedis = pool.getResource();
208 } catch (JedisConnectionException e) {
209 LOG.error(e);
210 borrowOrOprSuccess = false;
211 if (jedis != null) {
212 pool.returnBrokenResource(jedis);
213 }
214 } finally {
215 if (borrowOrOprSuccess) {
216 pool.returnResource(jedis);
217 }
218 }
219 jedis = pool.getResource();
220 return jedis;
221 }
222
223 public JedisPool getJedisPool() {
224 return this.pool;
225 }
226
227 }
228
229 private static class SerializeUtil {
230 public static byte[] serialize(Object object) {
231 ObjectOutputStream oos = null;
232 ByteArrayOutputStream baos = null;
233 byte[] bytes = null;
234 try {
235 // 序列化
236 baos = new ByteArrayOutputStream();
237 oos = new ObjectOutputStream(baos);
238 oos.writeObject(object);
239 bytes = baos.toByteArray();
240 return bytes;
241 } catch (Exception e) {
242 LOG.error(e);
243 }
244 return bytes;
245 }
246
247 public static Object unserialize(byte[] bytes) {
248 if (bytes == null) {
249 return null;
250 }
251 ByteArrayInputStream bais = null;
252 try {
253 // 反序列化
254 bais = new ByteArrayInputStream(bytes);
255 ObjectInputStream ois = new ObjectInputStream(bais);
256 return ois.readObject();
257 } catch (Exception e) {
258 LOG.error(e);
259 }
260 return null;
261 }
262 }
263}
新建LoggingRedisCache.java类
该类继承了org.apache.ibatis.cache.decorators.LoggingCache,是缓存的入口类
1public class LoggingRedisCache extends LoggingCache {
2 public LoggingRedisCache(String id) {
3 super(new RedisCache(id));
4 }
5}
使用缓存
在需要使用缓存的mapper文件中加入(要在<mapper>标签范围内):
1<cache type="cn.essa.component.privilege.cache.LoggingRedisCache" />
注意:测试时请记得开启redis
