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); } }