SSM+redis整合java
這裏主要是利用redis去作mybatis的二級緩存,mybaits映射文件中全部的select都會刷新已有緩存,若是不存在就會新建緩存,全部的insert,update操做都會更新緩存。mysql
redis的好處也顯而易見,能夠使系統的數據訪問性能更高。本節只是展現了整合方法和效果,後面會補齊redis集羣、負載均衡和session共享的文章。linux
下面就開始整合工做:web
後臺首先啓動redis-server(後臺啓動與遠程鏈接linux服務的方法都須要改redis.conf文件),啓動命令「./src/redis-server ./redis.conf」redis
我這裏是windows系統下開發的,推薦一個可視化工具「Redis Desktop manager」,須要遠程鏈接linux下的redis,須要linux下開啓端口對外開放(具體方法是修改/etc/sysconfig/iptables文件,增長對外端口開發命令)。spring
以上操做都完成後,便可遠程鏈接成功了,如圖:sql
如今尚未緩存記錄,下面進入代碼階段,首先在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.propertiesapache
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.xmlwindows
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進行查詢。