采用redis作为独立缓存服务器(一)
2018-02-03 00:54
891 查看
读者注意:接上篇,请先阅读上篇。
一 环境
基础环境:jdk1.7+spring3.2.9+mybatis3.2.2+redis3.2.8+mysql5.6
引入额外的依赖
spring-data-redis-1.3.1.RELEASE.jar
jedis-2.4.1.jar
commons-pool2-2.0.jar
附加工具及验证工具:
centos6.5 64位 + SecureCRT6.7 + RedisDesktopManager0.8.8
二 服务器架构
三 关键代码
=======================redis参数配置=====================================
======================spring配置=========================
Mybatis为了方便我们扩展缓存定义了一个Cache接口,看看ehcache-mybatis的源码就明白了。我们要使用自己的cache同样的实现Cache接口即可。
===============================
在看ehcache-mybatis的源码 它真正使用cache的方式是通过集成org.apache.ibatis.cache.decorators.LoggingCache 这个类实现的,所以我们也继承
在mapper.xml中添加如下cache标签
在mybatis核心配置文件中启用缓存功能
四 验证
应用程序运行前,缓存服务器里面没有任何缓存,如图
进行登录操作,并进入综合查询页码
这中间会经历4个sql语句
select * from users where userName=? and passWord=?
SELECT s.stuId,s.stuName,s.gender,s.age,s.address,d.departName FROM student s inner join department d on s.deptidd=d.deptid where 1=1
ORDER BY AGE DESC
LIMIT ?,?
SELECT count(*) FROM student s inner join department d on s.deptidd=d.deptid where 1=1
select departName from department
然后我们可以看到缓存服务器上就会有对应的4个键值对
直接从linux服务器上看
从运行结果上看,先从缓存取,没取到从数据库取,然后存入缓存
从redis图形管理界面也可以看出
往后翻,发现一个sql一个key
再次运行同样的sql,发现只从缓存取数据了,而没必要从数据库取数据了
证明独立缓存集成配置成功!!!
这里有个问题,如果进行增删改操作,会默认删除所有的缓存,而不是按照mapper的命名空间刷新缓存,如果有读者解决了这个问题请留言告诉我,感激不尽!!!
该缓存解决方案并不能实现对缓存的精确控制!
比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,
但是要求用户每次都能查询最新的商品信息,此时就无法实现当一个商品变化时
只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,
当一个商品信息变化会将所有商品信息的缓存数据全部清空。
解决此类问题需要在业务层根据需求对数据有针对性缓存。
请读者继续阅读我的后面的博文,会提供相应解决方案!!!
一 环境
基础环境:jdk1.7+spring3.2.9+mybatis3.2.2+redis3.2.8+mysql5.6
引入额外的依赖
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.3.1.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.4.1</version> </dependency>maven会自动添加上如下依赖包:
spring-data-redis-1.3.1.RELEASE.jar
jedis-2.4.1.jar
commons-pool2-2.0.jar
附加工具及验证工具:
centos6.5 64位 + SecureCRT6.7 + RedisDesktopManager0.8.8
二 服务器架构
三 关键代码
=======================redis参数配置=====================================
#*****************jedis连接参数设置********************* #redis服务器ip redis.ip=169.254.130.122 #redis服务器端口号 redis.port=6379 #redis访问密码 redis.passWord=test123 #与服务器建立连接的超时时间 redis.timeout=3000 #************************jedis池参数设置******************* #jedis的最大活跃连接数 jedis.pool.maxActive=50 #jedis最大空闲连接数 jedis.pool.maxIdle=10 #jedis池没有连接对象返回时,等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。 #如果超过等待时间,则直接抛出JedisConnectionException jedis.pool.maxWait=1500 #从池中获取连接的时候,是否进行有效检查 jedis.pool.testOnBorrow=true #归还连接的时候,是否进行有效检查 jedis.pool.testOnReturn=true
======================spring配置=========================
<?xml version="1.0" encoding="UTF-8"?> <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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <import resource="classpath:configs/spring/applicationContext-*.xml"/> <bean id="config" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:configs/druidConfig.properties</value> <value>classpath:configs/redis.properties</value> </list> </property> </bean> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${driverClassName}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <property name="filters" value="${filters}" /> <property name="initialSize" value="${initialSize}" /> <property name="maxActive" value="${maxActive}" /> <property name="minIdle" value="${minIdle}" /> <property name="maxWait" value="${maxWait}" /> <property name="validationQuery" value="${validationQuery}" /> <property name="testWhileIdle" value="${testWhileIdle}" /> <property name="testOnBorrow" value="${testOnBorrow}" /> <property name="testOnReturn" value="${testOnReturn}" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}" /> <property name="removeAbandoned" value="${removeAbandoned}" /> <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> </bean> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="druidDataSource"></property> <property name="configLocation"> <value>classpath:configs/mybatis-config.xml</value> </property> <property name="mapperLocations"> <list> <value>classpath:com/wx/entitys/*.xml</value> </list> </property> </bean> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFactory" ref="sessionFactory"></constructor-arg> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druidDataSource"></property> </bean> <tx:advice id="txAdvise" transaction-manager="txManager"> <tx:attributes> <tx:method name="find*" read-only="true"/> <tx:method name="search*" read-only="true"/> <tx:method name="query*" read-only="true"/> <tx:method name="get*" read-only="true"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="do*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut expression="execution(* com.wx.service.*.*(..))" id="myCut"/> <aop:advisor advice-ref="txAdvise" pointcut-ref="myCut"/> </aop:config> <!-- 配置redis 单机版 start--> <!-- redis数据源 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大空闲数 --> <property name="maxIdle" value="${jedis.pool.maxIdle}" /> <!-- 最大活跃数 --> <property name="maxTotal" value="${jedis.pool.maxActive}" /> <!-- 最大等待时间 --> <property name="maxWaitMillis" value="${jedis.pool.maxWait}" /> <!-- 返回连接时,检测连接是否成功 --> <property name="testOnBorrow" value="${jedis.pool.testOnBorrow}" /> </bean> <!-- Spring-redis连接池管理工厂 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!-- IP地址 --> <property name="hostName" value="${redis.ip}" /> <!-- 端口号 --> <property name="port" value="${redis.port}" /> <!-- 密码 --> <property name="password" value="${redis.passWord}"/> <!-- 超时时间 --> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="poolConfig" /> </bean> <!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 --> <bean id="redisCacheTransfer" class="com.wx.utils.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/> </bean> <!-- 单机版Redis集成 End --> </beans>
Mybatis为了方便我们扩展缓存定义了一个Cache接口,看看ehcache-mybatis的源码就明白了。我们要使用自己的cache同样的实现Cache接口即可。
package com.wx.utils; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ibatis.cache.Cache; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; public class RedisCache implements Cache { private static JedisConnectionFactory jedisConnectionFactory; private final String id; private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public RedisCache(final String id){ if (id == null) { throw new IllegalArgumentException("cache instances require an ID"); } this.id = id; } /** * 缓存的清除策略,只要有增删改操作,那么就会自动调用它 ,如果不需要,请注释掉 */ public void clear() { RedisConnection connection = null; try { connection=jedisConnectionFactory.getConnection(); connection.flushDb(); connection.flushAll(); System.out.println("缓存被清空了...."); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } } @Override public String getId() { return this.id; } @Override public Object getObject(Object key) { System.out.println("--------------------------------get_key==>"+key+"<=="); Object result = null; //JedisConnection connection = null; RedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } @Override public int getSize() { int result = 0; //JedisConnection connection = null; RedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); result = Integer.valueOf(connection.dbSize().toString()); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } @Override public void putObject(Object key, Object value) { System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>put_key===>"+key+"<==="); //JedisConnection connection = null; RedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); System.out.println("**"+serializer.serialize(key)); connection.set(serializer.serialize(key), serializer.serialize(value)); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } } @Override public Object removeObject(Object key) { //JedisConnection connection = null; RedisConnection connection=null; Object result = null; try { System.out.println("===>"+key+"一个缓存被删除了"); connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = connection.expireAt(serializer.serialize(key), 0); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection != null) { connection.close(); } } return result; } public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } }========================
package com.wx.utils; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; //该类用于JedisConnectionFactory对象的注入 public class RedisCacheTransfer { public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.setJedisConnectionFactory(jedisConnectionFactory); } }
===============================
在看ehcache-mybatis的源码 它真正使用cache的方式是通过集成org.apache.ibatis.cache.decorators.LoggingCache 这个类实现的,所以我们也继承
package com.wx.utils; import org.apache.ibatis.cache.decorators.LoggingCache; public class LoggingRedisCache extends LoggingCache{ public LoggingRedisCache(String id) { super(new RedisCache(id)); } }
在mapper.xml中添加如下cache标签
<!-- 支持缓存配置 --> <cache type="com.wx.utils.LoggingRedisCache" />
在mybatis核心配置文件中启用缓存功能
<!-- 配置mybatis的缓存,延迟加载等相关属性 --> <settings> <!-- 是否开启全局缓存 --> <setting name="cacheEnabled" value="true"/> <!-- 查询时,关闭关联对象即时加载以提高性能 --> <setting name="lazyLoadingEnabled" value="false"/> <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 --> <setting name="aggressiveLazyLoading" value="true"/> <!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 --> <setting name="defaultExecutorType" value="REUSE" /> <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 --> <setting name="multipleResultSetsEnabled" value="true"/> </settings>
四 验证
应用程序运行前,缓存服务器里面没有任何缓存,如图
进行登录操作,并进入综合查询页码
这中间会经历4个sql语句
select * from users where userName=? and passWord=?
SELECT s.stuId,s.stuName,s.gender,s.age,s.address,d.departName FROM student s inner join department d on s.deptidd=d.deptid where 1=1
ORDER BY AGE DESC
LIMIT ?,?
SELECT count(*) FROM student s inner join department d on s.deptidd=d.deptid where 1=1
select departName from department
然后我们可以看到缓存服务器上就会有对应的4个键值对
直接从linux服务器上看
从运行结果上看,先从缓存取,没取到从数据库取,然后存入缓存
从redis图形管理界面也可以看出
往后翻,发现一个sql一个key
再次运行同样的sql,发现只从缓存取数据了,而没必要从数据库取数据了
证明独立缓存集成配置成功!!!
这里有个问题,如果进行增删改操作,会默认删除所有的缓存,而不是按照mapper的命名空间刷新缓存,如果有读者解决了这个问题请留言告诉我,感激不尽!!!
该缓存解决方案并不能实现对缓存的精确控制!
比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,
但是要求用户每次都能查询最新的商品信息,此时就无法实现当一个商品变化时
只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,
当一个商品信息变化会将所有商品信息的缓存数据全部清空。
解决此类问题需要在业务层根据需求对数据有针对性缓存。
请读者继续阅读我的后面的博文,会提供相应解决方案!!!
相关文章推荐
- 采用redis作为独立缓存服务器(二)_spring Cache应用
- 采用redis作为独立缓存服务器(三)_spring Cache后传之aop优化
- Redis作为缓存服务器
- redis作为mysql的缓存服务器(读写分离)
- redis作为mysql的缓存服务器(读写分离)
- redis作为mysql的缓存服务器(读写分离) (转)
- redis作为mysql的缓存服务器(读写分离) (转)
- redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)
- redis作为mysql的缓存服务器(读写分离)
- 用Redis作为缓存服务器,加快数据库操作速度
- redis作为mysql的缓存服务器(读写分离)
- redis作为mysql的缓存服务器(读写分离) 推荐
- redis作为mysql的缓存服务器(读写分离)
- 001-Springboot从数据库读取配置文件并启动Redis作为缓存服务器
- redis作为缓存服务器
- spring-boot 整合redis作为数据缓存
- php使用redis作为session存储
- SpringBank 开发日志 Mybatis 使用redis 作为二级缓存时,无法通过cacheEnabled=false 将其关闭
- 为什么学习Redis作为消息队列服务器
- Android NDK rb5 文档之使用 Android 工具链作为一个独立编译器