SSM+redis整合

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

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

下面就开始整合工作:

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

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

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

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

 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>

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

redis.host=192.168.0.109
redis.port=6379
redis.pass=123456
redis.maxIdle=200
redis.maxActive=1024
redis.maxWait=10000
redis.testOnBorrow=true

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

 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>

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

JedisClusterFactory.java

  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 }

RedisCache.java

  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 }

RedisCacheTransfer.java

 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 }

SerializeUtil.java

 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 }

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

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

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

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

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

redis与ssm整合(用 redis 替代mybatis二级缓存)的更多相关文章

  1. Spring Boot 入门(十):集成Redis哨兵模式,实现Mybatis二级缓存

    本片文章续<Spring Boot 入门(九):集成Quartz定时任务>.本文主要基于redis实现了mybatis二级缓存.较redis缓存,mybaits自带缓存存在缺点(自行谷歌) ...

  2. mybatis二级缓存应用及与ehcache整合

    mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存. 1.开启mybatis的二级缓存 在核心配 ...

  3. Springboot整合Ehcache 解决Mybatis二级缓存数据脏读 -详细

    前面有写了一篇关于这个,但是这几天又改进了一点,就单独一篇在详细说明一下 配置 application.properties ,启用Ehcache # Ehcache缓存 spring.cache.t ...

  4. Mybatis 二级缓存应用 (21)

    [MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...

  5. mybatis二级缓存

    二级缓存区域是根据mapper的namespace划分的,相同namespace的mapper查询数据放在同一个区域,如果使用mapper代理方法每个mapper的namespace都不同,此时可以理 ...

  6. 深入了解MyBatis二级缓存

    深入了解MyBatis二级缓存 标签: mybatis二级缓存 2015-03-30 08:57 41446人阅读 评论(13) 收藏 举报  分类: Mybatis(51)  版权声明:版权归博主所 ...

  7. MyBatis二级缓存配置

    正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 Mybatis二级缓存是SessionFactory,如果两次查询基于同一个SessionFactory,那么就从二级缓存 ...

  8. 如何细粒度地控制你的MyBatis二级缓存(mybatis-enhanced-cache插件实现)

    前几天网友chanfish 给我抛出了一个问题,笼统地讲就是如何能细粒度地控制MyBatis的二级缓存问题,酝酿了几天,觉得可以写个插件来实现这个这一功能.本文就是从问题入手,一步步分析现存的MyBa ...

  9. MyBatis 二级缓存全详解

    目录 MyBatis 二级缓存介绍 二级缓存开启条件 探究二级缓存 二级缓存失效的条件 第一次SqlSession 未提交 更新对二级缓存影响 探究多表操作对二级缓存的影响 二级缓存源码解析 二级缓存 ...

随机推荐

  1. 如何给echarts图表添加下载图表成图片的功能

    先打开一个现成的图表效果图,注意图中圈出的地方,如图   打开源码找到option,如图   在option下添加toolbox,如图   在toolbox下添加feature,如图   在featu ...

  2. mime设置

    ie9对mime有特殊要求,必须要有type才可以. 如果出现css的mime类型不支持.则没有加 type="css/text" 查看本机的mime支持: regedit > ...

  3. Java 跨域 CrossOrigin注解 Filter拦截 Nginx配置

    说明 资源请求的发起方与请求的资源不在同一个域中的: 一般的,只要网站的[协议名protocol].[主机host].[端口号port]这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用: ...

  4. Mybatis知识(2)

    1.#{}和${}的区别是什么? 注:这道题是面试官面试我同事的. 答:${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静 ...

  5. HttpClient post封装

    /** * @title HttpUtils * @description post请求封装 * @author maohuidong * @date 2017-12-18 */ public sta ...

  6. Jsonlib 属性过滤器

    /** * @title JSON转换属性过滤器 * @description 用于JSON lib的JSON转换 * @author maohuidong * @date 2017-04-06 */ ...

  7. 【转】Phong和Blinn-Phong光照模型

    来自:http://www.cnblogs.com/bluebean/p/5299358.html Phong和Blinn-Phong是计算镜面反射光的两种光照模型,两者仅仅有很小的不同之处. 1.P ...

  8. Nginx打开目录浏览功能(autoindex)以及常见问题解决方案

    Nginx默认是不允许列出整个目录的.如需此功能,打开nginx.conf文件,在location server 或 http段中加入autoindex on;另外两个参数最好也加上去: autoin ...

  9. 在SQL Server中使用CLR调用.NET方法

    介绍    我们一起来做个示例,在.NET中新建一个类,并在这个类里新建一个方法,然后在SQL Server中调用这个方法.按照微软所述,通过宿主 Microsoft .NET Framework 2 ...

  10. maven 的聚合