redis与ssm整合(用 redis 替代mybatis二级缓存)

SSM+redis整合

这里主要是利用redis去做mybatis的二级缓存,mybaits映射文件中所有的select都会刷新已有缓存,如果不存在就会新建缓存,所有的insert,update操作都会更新缓存。

redis的好处也显而易见,可以使系统的数据访问性能更高。本节只是展示了整合方法和效果,后面会补齐redis集群、负载均衡和session共享的文章。

下面就开始整合工作:

redis与ssm整合(用 redis 替代mybatis二级缓存)

后台首先启动redis-server(后台启动与远程连接linux服务的方法都需要改redis.conf文件),启动命令“./src/redis-server ./redis.conf”

我这里是windows系统下开发的,推荐一个可视化工具“Redis Desktop manager”,需要远程连接linux下的redis,需要linux下开启端口对外开放(具体方法是修改/etc/sysconfig/iptables文件,增加对外端口开发命令)。

以上操作都完成后,即可远程连接成功了,如图:

redis与ssm整合(用 redis 替代mybatis二级缓存)

redis与ssm整合(用 redis 替代mybatis二级缓存)

现在还没有缓存记录,下面进入代码阶段,首先在pom.xml中增加需要的redis jar包

redis与ssm整合(用 redis 替代mybatis二级缓存)
 1 <dependency>
2 <groupId>redis.clients</groupId>
3 <artifactId>jedis</artifactId>
4 <version>2.9.0</version>
5 </dependency>
6
7 <dependency>
8 <groupId>org.springframework.data</groupId>
9 <artifactId>spring-data-redis</artifactId>
10 <version>1.6.2.RELEASE</version>
11 </dependency>
12
13 <dependency>
14 <groupId>org.mybatis</groupId>
15 <artifactId>mybatis-ehcache</artifactId>
16 <version>1.0.0</version>
17 </dependency>
18 <!-- 添加druid连接池包 -->
19 <dependency>
20 <groupId>com.alibaba</groupId>
21 <artifactId>druid</artifactId>
22 <version>1.0.24</version>
23 </dependency>
redis与ssm整合(用 redis 替代mybatis二级缓存)

pom.xml写好后,还需要新增两个配置文件:redis.properties

redis与ssm整合(用 redis 替代mybatis二级缓存)
redis.host=192.168.0.109
redis.port=6379
redis.pass=123456
redis.maxIdle=200
redis.maxActive=1024
redis.maxWait=10000
redis.testOnBorrow=true
redis与ssm整合(用 redis 替代mybatis二级缓存)

其中字段也都很好理解,再加入配置文件:spring-redis.xml

redis与ssm整合(用 redis 替代mybatis二级缓存)
 1 <beans xmlns="http://www.springframework.org/schema/beans"
2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns:p="http://www.springframework.org/schema/p"
4 xmlns:mvc="http://www.springframework.org/schema/mvc"
5 xmlns:util="http://www.springframework.org/schema/util"
6 xmlns:aop="http://www.springframework.org/schema/aop"
7 xmlns:context="http://www.springframework.org/schema/context"
8 xmlns:task="http://www.springframework.org/schema/task"
9 xsi:schemaLocation="http://www.springframework.org/schema/beans
10 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
11 http://www.springframework.org/schema/util
12 http://www.springframework.org/schema/util/spring-util-4.3.xsd
13 http://www.springframework.org/schema/mvc
14 http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
15 http://www.springframework.org/schema/aop
16 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
17 http://www.springframework.org/schema/context
18 http://www.springframework.org/schema/context/spring-context-4.3.xsd">
19
20
21 <!-- 连接池基本参数配置,类似数据库连接池 -->
22 <context:property-placeholder location="classpath*:redis.properties" />
23
24 <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
25 <property name="maxTotal" value="${redis.maxActive}"/>
26 <property name="maxIdle" value="${redis.maxIdle}" />
27 <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
28 </bean>
29
30 <!-- 连接池配置,类似数据库连接池 -->
31 <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
32 <property name="hostName" value="${redis.host}"></property>
33 <property name="port" value="${redis.port}"></property>
34 <property name="password" value="${redis.pass}"></property>
35 <property name="poolConfig" ref="poolConfig"></property>
36 </bean>
37
38 <!-- 调用连接池工厂配置 -->
39 <!-- <bean id="redisTemplate" class=" org.springframework.data.redis.core.RedisTemplate">
40 <property name="jedisConnectionFactory" ref="jedisConnectionFactory"></property>
41
42 如果不配置Serializer,那么存储的时候智能使用String,如果用User类型存储,那么会提示错误User can't cast to String!!!
43 <property name="keySerializer">
44 <bean
45 class="org.springframework.data.redis.serializer.StringRedisSerializer" />
46 </property>
47 <property name="valueSerializer">
48 <bean
49 class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
50 </property>
51 </bean> -->
52 <bean id="redisCacheTransfer" class="com.cjl.util.RedisCacheTransfer">
53 <property name="jedisConnectionFactory" ref="jedisConnectionFactory" />
54 </bean>
55 </beans>
redis与ssm整合(用 redis 替代mybatis二级缓存)

配置文件写好后,就开始java代码的编写:

JedisClusterFactory.java

redis与ssm整合(用 redis 替代mybatis二级缓存)
  1 package com.cjl.util;
2
3 import java.util.HashSet;
4 import java.util.Properties;
5 import java.util.Set;
6 import java.util.regex.Pattern;
7
8 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
9 import org.springframework.beans.factory.FactoryBean;
10 import org.springframework.beans.factory.InitializingBean;
11 import org.springframework.core.io.Resource;
12
13 import redis.clients.jedis.HostAndPort;
14 import redis.clients.jedis.JedisCluster;
15
16 public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {
17
18 private Resource addressConfig;
19 private String addressKeyPrefix;
20
21 private JedisCluster jedisCluster;
22 private Integer timeout;
23 private Integer maxRedirections;
24 private GenericObjectPoolConfig genericObjectPoolConfig;
25
26 private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");
27
28 public JedisCluster getObject() throws Exception {
29 return jedisCluster;
30 }
31
32 public Class<? extends JedisCluster> getObjectType() {
33 return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);
34 }
35
36 public boolean isSingleton() {
37 return true;
38 }
39
40 private Set<HostAndPort> parseHostAndPort() throws Exception {
41 try {
42 Properties prop = new Properties();
43 prop.load(this.addressConfig.getInputStream());
44
45 Set<HostAndPort> haps = new HashSet<HostAndPort>();
46 for (Object key : prop.keySet()) {
47
48 if (!((String) key).startsWith(addressKeyPrefix)) {
49 continue;
50 }
51
52 String val = (String) prop.get(key);
53
54 boolean isIpPort = p.matcher(val).matches();
55
56 if (!isIpPort) {
57 throw new IllegalArgumentException("ip 或 port 不合法");
58 }
59 String[] ipAndPort = val.split(":");
60
61 HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
62 haps.add(hap);
63 }
64
65 return haps;
66 } catch (IllegalArgumentException ex) {
67 throw ex;
68 } catch (Exception ex) {
69 throw new Exception("解析 jedis 配置文件失败", ex);
70 }
71 }
72
73 public void afterPropertiesSet() throws Exception {
74 Set<HostAndPort> haps = this.parseHostAndPort();
75
76 jedisCluster = new JedisCluster(haps, timeout, maxRedirections, genericObjectPoolConfig);
77
78 }
79
80 public void setAddressConfig(Resource addressConfig) {
81 this.addressConfig = addressConfig;
82 }
83
84 public void setTimeout(int timeout) {
85 this.timeout = timeout;
86 }
87
88 public void setMaxRedirections(int maxRedirections) {
89 this.maxRedirections = maxRedirections;
90 }
91
92 public void setAddressKeyPrefix(String addressKeyPrefix) {
93 this.addressKeyPrefix = addressKeyPrefix;
94 }
95
96 public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
97 this.genericObjectPoolConfig = genericObjectPoolConfig;
98 }
99
100 }
redis与ssm整合(用 redis 替代mybatis二级缓存)

RedisCache.java

redis与ssm整合(用 redis 替代mybatis二级缓存)
  1 package com.cjl.util;
2
3 import java.util.concurrent.locks.ReadWriteLock;
4 import java.util.concurrent.locks.ReentrantReadWriteLock;
5
6 import org.apache.ibatis.cache.Cache;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9 import org.springframework.data.redis.connection.jedis.JedisConnection;
10 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
11 import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
12 import org.springframework.data.redis.serializer.RedisSerializer;
13
14 import redis.clients.jedis.exceptions.JedisConnectionException;
15
16 public class RedisCache implements Cache {
17 private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
18
19 private static JedisConnectionFactory jedisConnectionFactory;
20
21 private final String id;
22
23 private final ReadWriteLock rwl = new ReentrantReadWriteLock();
24
25
26 public RedisCache(final String id) {
27 if (id == null) {
28 throw new IllegalArgumentException("Cache instances require an ID");
29 }
30 logger.debug("MybatisRedisCache:id=" + id);
31 this.id = id;
32 }
33
34 /**
35 * 清空所有缓存
36 */
37 public void clear() {
38 rwl.readLock().lock();
39 JedisConnection connection = null;
40 try {
41 connection = jedisConnectionFactory.getConnection();
42 connection.flushDb();
43 connection.flushAll();
44 } catch (JedisConnectionException e) {
45 e.printStackTrace();
46 } finally {
47 if (connection != null) {
48 connection.close();
49 }
50 rwl.readLock().unlock();
51 }
52 }
53
54 public String getId() {
55 return this.id;
56 }
57
58 /**
59 * 获取缓存总数量
60 */
61 public int getSize() {
62 int result = 0;
63 JedisConnection connection = null;
64 try {
65 connection = jedisConnectionFactory.getConnection();
66 result = Integer.valueOf(connection.dbSize().toString());
67 logger.info("添加mybaits二级缓存数量:" + result);
68 } catch (JedisConnectionException e) {
69 e.printStackTrace();
70 } finally {
71 if (connection != null) {
72 connection.close();
73 }
74 }
75 return result;
76 }
77
78 public void putObject(Object key, Object value) {
79 rwl.writeLock().lock();
80
81 JedisConnection connection = null;
82 try {
83 connection = jedisConnectionFactory.getConnection();
84 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
85 connection.set(SerializeUtil.serialize(key), SerializeUtil.serialize(value));
86 logger.info("添加mybaits二级缓存key=" + key + ",value=" + value);
87 } catch (JedisConnectionException e) {
88 e.printStackTrace();
89 } finally {
90 if (connection != null) {
91 connection.close();
92 }
93 rwl.writeLock().unlock();
94 }
95 }
96
97 public Object getObject(Object key) {
98 // 先从缓存中去取数据,先加上读锁
99 rwl.readLock().lock();
100 Object result = null;
101 JedisConnection connection = null;
102 try {
103 connection = jedisConnectionFactory.getConnection();
104 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
105 result = serializer.deserialize(connection.get(serializer.serialize(key)));
106 logger.info("命中mybaits二级缓存,value=" + result);
107
108 } catch (JedisConnectionException e) {
109 e.printStackTrace();
110 } finally {
111 if (connection != null) {
112 connection.close();
113 }
114 rwl.readLock().unlock();
115 }
116 return result;
117 }
118
119 public Object removeObject(Object key) {
120 rwl.writeLock().lock();
121
122 JedisConnection connection = null;
123 Object result = null;
124 try {
125 connection = jedisConnectionFactory.getConnection();
126 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
127 result = connection.expire(serializer.serialize(key), 0);
128 } catch (JedisConnectionException e) {
129 e.printStackTrace();
130 } finally {
131 if (connection != null) {
132 connection.close();
133 }
134 rwl.writeLock().unlock();
135 }
136 return result;
137 }
138
139 public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
140 RedisCache.jedisConnectionFactory = jedisConnectionFactory;
141 }
142
143 public ReadWriteLock getReadWriteLock() {
144 // TODO Auto-generated method stub
145 return rwl;
146 }
147
148 }
redis与ssm整合(用 redis 替代mybatis二级缓存)

RedisCacheTransfer.java

redis与ssm整合(用 redis 替代mybatis二级缓存)
 1 package com.cjl.util;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
5
6 /**
7 * 静态注入中间类
8 */
9 public class RedisCacheTransfer {
10 @Autowired
11 public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
12 RedisCache.setJedisConnectionFactory(jedisConnectionFactory);
13 }
14
15 }
redis与ssm整合(用 redis 替代mybatis二级缓存)

SerializeUtil.java

redis与ssm整合(用 redis 替代mybatis二级缓存)
 1 package com.cjl.util;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.ObjectInputStream;
6 import java.io.ObjectOutputStream;
7
8 /**
9 *
10 * @author cjl
11 *
12 */
13 public class SerializeUtil {
14 /**
15 * 序列化
16 */
17 public static byte[] serialize(Object object) {
18 ObjectOutputStream oos = null;
19 ByteArrayOutputStream baos = null;
20 try {
21 // 序列化
22 baos = new ByteArrayOutputStream();
23 oos = new ObjectOutputStream(baos);
24 oos.writeObject(object);
25 byte[] bytes = baos.toByteArray();
26 return bytes;
27 } catch (Exception e) {
28 e.printStackTrace();
29 }
30 return null;
31 }
32
33 /**
34 *反序列化
35 */
36 public static Object unserialize(byte[] bytes) {
37 if (bytes !=null) {
38 ByteArrayInputStream bais = null;
39 try {
40 // 反序列化
41 bais = new ByteArrayInputStream(bytes);
42 ObjectInputStream ois = new ObjectInputStream(bais);
43 return ois.readObject();
44 } catch (Exception e) {
45
46 }
47 }
48 return null;
49 }
50 }
redis与ssm整合(用 redis 替代mybatis二级缓存)

所有东西准备齐全后还需要修改映射文件

redis与ssm整合(用 redis 替代mybatis二级缓存)

要使mybaits缓存生效,还需如上图这样开启二级缓存。配置文件还需要在web.xml中加载生效

redis与ssm整合(用 redis 替代mybatis二级缓存)

一切准备就绪后,启动服务

启动成功后,点击员工表单可以触发查询所有员工的方法,第一次进行查询语句可以看到mybatis打印了查询语句,并在redis服务器中更新了一条缓存

redis与ssm整合(用 redis 替代mybatis二级缓存)

我们清空控制台再次点击查询员工按钮执行查询方法,可以看到没有执行查询语句,证明第二次查询直接从缓存中取值,没有连接mysql进行查询。

上一篇:libuv 简单使用


下一篇:专业分析docker的分层存储技术