redis与ssm整合方法(mybatis二级缓存)
ssm+redis整合
ssm框架之前已经搭建过了,这里不再做代码复制工作。
这里主要是利用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包
<dependency> <groupid>redis.clients</groupid> <artifactid>jedis</artifactid> <version>2.9.0</version> </dependency> <dependency> <groupid>org.springframework.data</groupid> <artifactid>spring-data-redis</artifactid> <version>1.6.2.release</version> </dependency> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis-ehcache</artifactid> <version>1.0.0</version> </dependency> <!-- 添加druid连接池包 --> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid</artifactid> <version>1.0.24</version> </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
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 连接池基本参数配置,类似数据库连接池 --> <context:property-placeholder location="classpath*:redis.properties" /> <bean id="poolconfig" class="redis.clients.jedis.jedispoolconfig"> <property name="maxtotal" value="${redis.maxactive}"/> <property name="maxidle" value="${redis.maxidle}" /> <property name="testonborrow" value="${redis.testonborrow}"/> </bean> <!-- 连接池配置,类似数据库连接池 --> <bean id="jedisconnectionfactory" class="org.springframework.data.redis.connection.jedis.jedisconnectionfactory" > <property name="hostname" value="${redis.host}"></property> <property name="port" value="${redis.port}"></property> <property name="password" value="${redis.pass}"></property> <property name="poolconfig" ref="poolconfig"></property> </bean> <!-- 调用连接池工厂配置 --> <!-- <bean id="redistemplate" class=" org.springframework.data.redis.core.redistemplate"> <property name="jedisconnectionfactory" ref="jedisconnectionfactory"></property> 如果不配置serializer,那么存储的时候智能使用string,如果用user类型存储,那么会提示错误user can't cast to string!!! <property name="keyserializer"> <bean class="org.springframework.data.redis.serializer.stringredisserializer" /> </property> <property name="valueserializer"> <bean class="org.springframework.data.redis.serializer.jdkserializationredisserializer" /> </property> </bean> --> <bean id="rediscachetransfer" class="com.cjl.util.rediscachetransfer"> <property name="jedisconnectionfactory" ref="jedisconnectionfactory" /> </bean> </beans>
配置文件写好后,就开始java代码的编写:
jedisclusterfactory.java
package com.cjl.util; import java.util.hashset; import java.util.properties; import java.util.set; import java.util.regex.pattern; import org.apache.commons.pool2.impl.genericobjectpoolconfig; import org.springframework.beans.factory.factorybean; import org.springframework.beans.factory.initializingbean; import org.springframework.core.io.resource; import redis.clients.jedis.hostandport; import redis.clients.jedis.jediscluster; public class jedisclusterfactory implements factorybean<jediscluster>, initializingbean { private resource addressconfig; private string addresskeyprefix; private jediscluster jediscluster; private integer timeout; private integer maxredirections; private genericobjectpoolconfig genericobjectpoolconfig; private pattern p = pattern.compile("^.+[:]\\d{1,5}\\s*$"); public jediscluster getobject() throws exception { return jediscluster; } public class<? extends jediscluster> getobjecttype() { return (this.jediscluster != null ? this.jediscluster.getclass() : jediscluster.class); } public boolean issingleton() { return true; } private set<hostandport> parsehostandport() throws exception { try { properties prop = new properties(); prop.load(this.addressconfig.getinputstream()); set<hostandport> haps = new hashset<hostandport>(); for (object key : prop.keyset()) { if (!((string) key).startswith(addresskeyprefix)) { continue; } string val = (string) prop.get(key); boolean isipport = p.matcher(val).matches(); if (!isipport) { throw new illegalargumentexception("ip 或 port 不合法"); } string[] ipandport = val.split(":"); hostandport hap = new hostandport(ipandport[0], integer.parseint(ipandport[1])); haps.add(hap); } return haps; } catch (illegalargumentexception ex) { throw ex; } catch (exception ex) { throw new exception("解析 jedis 配置文件失败", ex); } } public void afterpropertiesset() throws exception { set<hostandport> haps = this.parsehostandport(); jediscluster = new jediscluster(haps, timeout, maxredirections, genericobjectpoolconfig); } public void setaddressconfig(resource addressconfig) { this.addressconfig = addressconfig; } public void settimeout(int timeout) { this.timeout = timeout; } public void setmaxredirections(int maxredirections) { this.maxredirections = maxredirections; } public void setaddresskeyprefix(string addresskeyprefix) { this.addresskeyprefix = addresskeyprefix; } public void setgenericobjectpoolconfig(genericobjectpoolconfig genericobjectpoolconfig) { this.genericobjectpoolconfig = genericobjectpoolconfig; } }
rediscache.java
package com.cjl.util; import java.util.concurrent.locks.readwritelock; import java.util.concurrent.locks.reentrantreadwritelock; import org.apache.ibatis.cache.cache; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.data.redis.connection.jedis.jedisconnection; import org.springframework.data.redis.connection.jedis.jedisconnectionfactory; import org.springframework.data.redis.serializer.jdkserializationredisserializer; import org.springframework.data.redis.serializer.redisserializer; import redis.clients.jedis.exceptions.jedisconnectionexception; public class rediscache implements cache { private static final logger logger = loggerfactory.getlogger(rediscache.class); private static jedisconnectionfactory jedisconnectionfactory; private final string id; private final readwritelock rwl = new reentrantreadwritelock(); public rediscache(final string id) { if (id == null) { throw new illegalargumentexception("cache instances require an id"); } logger.debug("mybatisrediscache:id=" + id); this.id = id; } /** * 清空所有缓存 */ public void clear() { rwl.readlock().lock(); jedisconnection connection = null; try { connection = jedisconnectionfactory.getconnection(); connection.flushdb(); connection.flushall(); } catch (jedisconnectionexception e) { e.printstacktrace(); } finally { if (connection != null) { connection.close(); } rwl.readlock().unlock(); } } public string getid() { return this.id; } /** * 获取缓存总数量 */ public int getsize() { int result = 0; jedisconnection connection = null; try { connection = jedisconnectionfactory.getconnection(); result = integer.valueof(connection.dbsize().tostring()); logger.info("添加mybaits二级缓存数量:" + result); } catch (jedisconnectionexception e) { e.printstacktrace(); } finally { if (connection != null) { connection.close(); } } return result; } public void putobject(object key, object value) { rwl.writelock().lock(); jedisconnection connection = null; try { connection = jedisconnectionfactory.getconnection(); redisserializer<object> serializer = new jdkserializationredisserializer(); connection.set(serializeutil.serialize(key), serializeutil.serialize(value)); logger.info("添加mybaits二级缓存key=" + key + ",value=" + value); } catch (jedisconnectionexception e) { e.printstacktrace(); } finally { if (connection != null) { connection.close(); } rwl.writelock().unlock(); } } public object getobject(object key) { // 先从缓存中去取数据,先加上读锁 rwl.readlock().lock(); object result = null; jedisconnection connection = null; try { connection = jedisconnectionfactory.getconnection(); redisserializer<object> serializer = new jdkserializationredisserializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); logger.info("命中mybaits二级缓存,value=" + result); } catch (jedisconnectionexception e) { e.printstacktrace(); } finally { if (connection != null) { connection.close(); } rwl.readlock().unlock(); } return result; } public object removeobject(object key) { rwl.writelock().lock(); jedisconnection connection = null; object result = null; try { connection = jedisconnectionfactory.getconnection(); redisserializer<object> serializer = new jdkserializationredisserializer(); result = connection.expire(serializer.serialize(key), 0); } catch (jedisconnectionexception e) { e.printstacktrace(); } finally { if (connection != null) { connection.close(); } rwl.writelock().unlock(); } return result; } public static void setjedisconnectionfactory(jedisconnectionfactory jedisconnectionfactory) { rediscache.jedisconnectionfactory = jedisconnectionfactory; } public readwritelock getreadwritelock() { // todo auto-generated method stub return rwl; } }
rediscachetransfer.java
package com.cjl.util; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.redis.connection.jedis.jedisconnectionfactory; /** * 静态注入中间类 */ public class rediscachetransfer { @autowired public void setjedisconnectionfactory(jedisconnectionfactory jedisconnectionfactory) { rediscache.setjedisconnectionfactory(jedisconnectionfactory); } }
serializeutil.java
package com.cjl.util; import java.io.bytearrayinputstream; import java.io.bytearrayoutputstream; import java.io.objectinputstream; import java.io.objectoutputstream; /** * * @author cjl * */ public class serializeutil { /** * 序列化 */ public static byte[] serialize(object object) { objectoutputstream oos = null; bytearrayoutputstream baos = null; try { // 序列化 baos = new bytearrayoutputstream(); oos = new objectoutputstream(baos); oos.writeobject(object); byte[] bytes = baos.tobytearray(); return bytes; } catch (exception e) { e.printstacktrace(); } return null; } /** *反序列化 */ public static object unserialize(byte[] bytes) { if (bytes !=null) { bytearrayinputstream bais = null; try { // 反序列化 bais = new bytearrayinputstream(bytes); objectinputstream ois = new objectinputstream(bais); return ois.readobject(); } catch (exception e) { } } return null; } }
所有东西准备齐全后还需要修改映射文件
要使mybaits缓存生效,还需如上图这样开启二级缓存。配置文件还需要在web.xml中加载生效
一切准备就绪后,启动服务
启动成功后,点击员工表单可以触发查询所有员工的方法,第一次进行查询语句可以看到mybatis打印了查询语句,并在redis服务器中更新了一条缓存
我们清空控制台再次点击查询员工按钮执行查询方法,可以看到没有执行查询语句,证明第二次查询直接从缓存中取值,没有连接mysql进行查询。
总结
以上所述是小编给大家介绍的redis与ssm整合方法(mybatis二级缓存),希望对大家有所帮助
推荐阅读