1、Redis环境java
Redis 官网 :http://redis.io/mysql
windows下载:https://github.com/dmajkic/redis/downloadslinux
一、文件解压缩git
二、启动Redis服务器github
三、启动Redis客户端redis
四、测试Redis缓存算法
redis-cli.exe -h 127.0.0.1 -p 6379spring
set keytest valuestest 根据key、value加入缓存sql
get keytest 根据key获取值数据库
flushall 清空全部缓存
五、设置Redis密码
六、conf配置文件
#是否之后台守护进程运行,默认为no, 取值yes, no daemonize no #pid文件存放路径 pidfile /var/run/redis.pid #配置redis端口,默认6379 port 6379 #绑定ip。默认绑定全部本机ip,通常用在服务器多ip下,能够只监听内网服务器ip,保证服务安全 bind 127.0.0.1 #sock文件 unixsocket /tmp/redis.sock #客户端超时时间,单位秒 timeout 300 #log级别,支持四个级别,debug,notice,verbose,warning loglevel verbose #log文件路径 logfile #log输出到标准设备,logs不写文件,输出到空设备,/deb/null logfile stdout #保存快照的频率,在多长时间内执行必定数量的写操做时,保存快照的频率,能够设置多个条件。若是都注释掉,则不作内存数据持久化。若是只是把redis只用做cache,不开启持久化功能 save <seconds> <changes> save 900 1 #是否使用压缩 rdbcompression #快照数据库名称 dbfilename #数据库存放路径 dir #redis主从 作法 在从上填上主的IP和端口号 主上不用作任何设置 slaveof <masterip> <masterport> #主库服务器口令,若是主服务器未打开requirepass,则不须要此项 masterauth <master-password> #在master服务器挂掉或者同步失败时,从服务器是否继续提供服务 slave-serve-stale-data yes #设置redis服务密码,若是开启,则客户端链接时须要 -a 指定密码,不然操做会提示无权限 requirepass foobared #命令更名,至关于linux alias,能够用改功能屏蔽一些危险命令 rename-command #最大链接数;0 表示不限制 maxclients 128 #最大使用内存(分配的内存),推荐生产环境下作相应调整,咱们用的是只用来作高速缓存,限制2G。默认状况下,redis会占用可用的全部内存 maxmemory <bytes> #过时策略,提供六种策略 maxmemory-policy volatile-lru volatile-lru //删除过时和lru 的key(默认值) allkeys-lru //删除lru算法的key volatile-random //随机删除即将过时key allkeys->random //随机删除 volatile-ttl //删除即将过时的 noeviction //永不过时,返回错误 #是否开启appendonlylog,开启的话每次写操做会记一条log。至关于mysql的binlog;不一样的是,每次redis启动都会读此文件构建完整数据。即便删除rdb文件,数据也是安全的 appendonly #日志文件的名称,默认appendonly.aof appendfilename appendonly.aof #异步写append file 的策略。相似mysql事物log写方式。三种 appendfsync appendfsync always //同步,每次写都要flush到磁盘,安全,速度慢。 appendfsync everysec //每秒写(默认值,推荐值)同mysql appendfsync no //交给操做系统去作flush的动做 #虚拟内存开关 vm-enabled no #swap文件,不一样redis swap文件不能共享。并且生产环境下,不建议放在tmp目录 vm-swap-file /tmp/redis.swap #vm大小限制。0:不限制,建议60-80% 可用内存大小 vm-max-memory 0 #根据缓存内容大小调整,默认32字节 vm-page-size 32 #page数。每 8 page,会占用1字节内存。vm-page-size * vm-pages 等于 swap 文件大小 vm-pages 134217728 #vm 最大io线程数。注意: 0 标志禁止使用vm vm-max-threads 4
2、实现Redis缓存
<!-- spring-redis实现 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <!-- redis客户端jar --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.0</version> </dependency>
三、引入applicationContext.xml中引入redis配置
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- redis数据源 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxActive}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <!-- Spring-redis链接池管理工厂 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>
<!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 --> <bean id="redisCacheTransfer" class="com.hsmdata.springTest.modules.cache.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/> </bean> </beans>
四、redis.properties配置文件
#============================# #==== Redis settings ====# #============================# #redis 服务器 IP redis.host=127.0.0.1 #redis 服务器端口 redis.port=6379 #redis 密码 redis.pass= #redis 支持16个数据库(至关于不一样用户)可使不一样的应用程序数据彼此分开同时又存储在相同的实例上 redis.dbIndex=3 #redis 缓存数据过时时间单位秒(3600*12 = 43 200) redis.expiration=43200 #控制一个 pool 最多有多少个状态为 idle 的jedis实例 redis.maxIdle=200 #控制一个 pool 可分配多少个jedis实例 redis.maxActive=1000 #当borrow一个jedis实例时,最大的等待时间,若是超过等待时间,则直接抛出JedisConnectionException; redis.maxWait=500 #在borrow一个jedis实例时,是否提早进行alidate操做;若是为true,则获得的jedis实例均是可用的; redis.testOnBorrow=true
五、建立缓存实现类RedisCache
package com.hsmdata.springTest.modules.cache; 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; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author * 2018-04-10 20:50 * $DESCRIPTION} */ public class RedisCache implements Cache { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private static JedisConnectionFactory jedisConnectionFactory; private final String id; /** * The {@code ReadWriteLock}. */ private final ReadWriteLock readWriteLock = 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; } @Override public void clear() { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); connection.flushDb(); connection.flushAll(); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } } @Override public String getId() { return this.id; } @Override public Object getObject(Object key) { Object result = null; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); } catch (JedisConnectionException 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; try { connection = jedisConnectionFactory.getConnection(); result = Integer.valueOf(connection.dbSize().toString()); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return result; } @Override public void putObject(Object key, Object value) { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); connection.set(serializer.serialize(key), serializer.serialize(value)); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } } @Override public Object removeObject(Object key) { 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(); } } return result; } public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } }
六、建立中间类RedisCacheTransfer,完成RedisCache.jedisConnectionFactory的静态注入
package com.hsmdata.springTest.modules.cache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; /** * @author * 2018-04-10 20:52 * $DESCRIPTION} */ public class RedisCacheTransfer { @Autowired public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.setJedisConnectionFactory(jedisConnectionFactory); } }
七、mapper中加入MyBatis二级缓存
<mapper namespace="com.hsmdata.springTest.modules.mapper.UserMapper" > <!--开启本mapper的二级缓存,隔10秒自动刷新缓存 flushInterval="10000" --> <cache type="com.hsmdata.springTest.modules.cache.RedisCache" />
八、Mybatis全局开启二级缓存
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 开启二级缓存,默认是false --> <setting name="cacheEnabled" value="true"/> <!--resultMap中的association和collection标签具备延迟加载的功能。--> <!--延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息。--> <!-- lazyLoadingEnabled:延迟加载启动,默认是false 全局性设置懒加载。若是设为‘false’,则全部相关联的都会被初始化加载。--> <setting name="lazyLoadingEnabled" value="false"/> <!-- aggressiveLazyLoading:积极的懒加载,false的话按需加载,默认是true 当设置为‘true’的时候,懒加载的对象可能被任何懒属性所有加载。不然,每一个属性都按需加载。--> <setting name="aggressiveLazyLoading" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="true"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25000"/> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> </configuration>
九、测试
package com.springTest.mybatis.cache; import com.hsmdata.springTest.modules.entity.User; import com.hsmdata.springTest.modules.mapper.UserMapper; import com.hsmdata.springTest.modules.service.UserService; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author * 2018-04-10 15:11 * $DESCRIPTION} */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:/config/applicationContext.xml", "classpath:/config/spring-servlet.xml"}) public class CacheTest { @Autowired private UserService userService; @Autowired private SqlSessionFactory sqlSessionFactory; /** * 同一个sqlSession */ @Test public void testFirstCache(){ SqlSession sqlSession=sqlSessionFactory.openSession(); UserMapper userMapper= sqlSession.getMapper(UserMapper.class); User user=userMapper.selectByPrimaryKey(56); System.out.println(user); /* 对sqlsession执行commit操做,也就意味着用户执行了update、delete等操做,那么数据库中的数据势必会发生变化,若是用户请求数据仍然使用以前内存中的数据,那么将读到脏数据。 因此在执行sqlsession操做后,会清除保存数据的HashMap,用户在发起查询请求时就会从新读取数据并放入一级缓存中了。*/ // sqlSession.commit(); user=userMapper.selectByPrimaryKey(56); System.out.println(user); } /** * 不一样的sqlSession */ @Test public void testSecondaryCache(){ SqlSession sqlSession=sqlSessionFactory.openSession(); UserMapper userMapper= sqlSession.getMapper(UserMapper.class); User user=userMapper.selectByPrimaryKey(56); System.out.println(user); // 即便开启了二级缓存,不一样的sqlsession之间的缓存数据也不是想互访就能互访的,必须等到sqlsession关闭了之后,才会把其一级缓存中的数据写入二级缓存。 // 关闭session // sqlSession.close(); // 经过sqlSessionFactory建立一个新的session sqlSession=sqlSessionFactory.openSession(); // 获取mapper对象 userMapper=sqlSession.getMapper(UserMapper.class); user=userMapper.selectByPrimaryKey(56); System.out.println(user); } /** * 不一样的sqlSession */ @Test public void testSecondaryCache2() { /* User user=new User("cache","123456","cache","","male",20); userService.insert(user);*/ User user = userService.get(56); System.out.println(user); User user1 = userService.get(56); System.out.println(user1); } @Test public void testFirstCache2() { /* User user=new User("cache","123456","cache","","male",20); userService.insert(user);*/ User user = userService.getTwo(56); System.out.println(user); } @Test public void testRedisCache(){ User user=userService.get(55); System.out.println(user); User user2=userService.get(56); System.out.println(user2); User user3=userService.get(55); System.out.println(user3); } }