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. Using Celery with Django

    参考1: http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html#using-celery-with-d ...

  2. 切换当前目录 pushd 和 popd

    切换当前目录@echo offc: & cd\ & md mp3       #在 C:\ 建立 mp3 文件夹md d:\mp4               #在 D:\ 建立 mp ...

  3. 多线程--Java

    多线程: 1.进程和线程 进程是资源分配的最小单位,线程是CPU调度的最小单位. 每个进程的创建都需要系统为其开辟资源内存空间,并发执行的程序在执行过程中分配和管理资源的基本单位,速度和销毁也较慢.进 ...

  4. 使用sqldeveloper连接服务器端数据库

  5. rem 响应 js函数

    size();window.onresize = function(){ size();}function size(){ var htnl_o=document.getElementsByTagNa ...

  6. 八月(The Summer is Gone)观后感

    第一次看到这部电影时觉得很亲近,黑白画面,国企改革的背景,浓浓的儿时画面感,原谅我只是一个三十不到的人,可能我比较早熟,对八九十年代还有些记忆,更早以前也通过电视.音乐.书籍等了解过一些,而那些听过又 ...

  7. c++中虚函数

    虽然很难找到一本不讨论多态性的C++书籍或杂志,但是,大多数这类讨论使多态性和C++虚函数的使用看起来很难.我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C++中的虚函数实现技术.说明一点 ...

  8. 协同过滤 spark scala

    1 http://www.cnblogs.com/charlesblc/p/6165201.html [转载]协同过滤 & Spark机器学习实战 2 基于Spark构建推荐引擎之一:基于物品 ...

  9. ubuntu中vim的设置

    问题:刚安装的VIM中,backspace不能删除字符,且上下左右箭头没反应. 解决方法: sudo vi  /etc/vim/vimrc.tiny 修改 set compatible为set noc ...

  10. FP真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IN_SALES_ORDER数据不带CZ

    错误描述:真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IT角度: IN_SALES_ORDER数据不带CZ 现时前台页面数据: 现时后台数据: 一.跟进情况 1.执行SAP_SALE ...