zoukankan      html  css  js  c++  java
  • 03.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包

     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进行查询。

    以上整合基本已经完成,如有不对的地方希望大家能够指出,后面会补上负载均衡和session共享。

  • 相关阅读:
    unittest详解 跳过用例的执行(skip)
    python 3 HTMLTestRunner.py文件
    jmeter 如何获取一小时之前的时间戳
    python]用eval强制将字符串转换为字典变量时候出错:NameError: name 'null' is not defined[python]用eval函数 字符串转dict
    Spring Boot 引入自定义yml
    关于爬虫与反爬虫简略方案
    网络回路问题
    MySQL添加新用户、为用户创建数据库、为新用户分配权限
    Spring Boot 项目几种启动方式
    Spring Cloud 之 基础学习资料
  • 原文地址:https://www.cnblogs.com/cuijiale/p/8012008.html
Copyright © 2011-2022 走看看