Redis緩存方案

1 Redis簡介
  Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。從2010年3月15日起,Redis的開發工做由VMware主持。
  redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set –有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步。
2 安裝
  2.1 安裝環境:
    CentOS 6.5
    Redis 2.8.13html

 

  2.2 下載安裝:
    下載文件到 /opt/ 目錄下
      wget http://download.redis.io/releases/redis-2.8.13.tar.gz
    解壓文件
      tar zxvf redis-2.8.13.tar.gz
    切換目錄到 redis-2.8.13 目錄下
      cd redis-2.8.13
    執行make命令,最後幾行的輸出結果
      Hint: To run ‘make test’ is a good ideajava

      make[1]: Leaving directory `/opt/redis-2.8.13/src’mysql

  2.3 執行安裝命令
    make install
  提示:
    cd src && make install
    make[1]: Entering directory `/opt/redis-2.8.13/src'linux

    Hint: To run 'make test' is a good ideagit

    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
    make[1]: Leaving directory `/opt/redis-2.8.13/src'
  根據提示,執行:cd src && make install
  提示:
  Hint: To run 'make test' is a good ideagithub

  INSTALL install
  INSTALL install
  INSTALL install
  INSTALL install
  INSTALL instal
  按照提示執行:make test
  提示:
    You need tcl 8.5 or newer in order to run the Redis test
   make: *** [test] Error 1
  解決方法參考:http://www.linuxfromscratch.org/blfs/view/cvs/general/tcl.htmlredis

3 Redis之java操做篇(Jedis)spring

  主要介紹如何用Jedis對Redis數據庫進行操做,只作了簡單的例子。前提:安裝好Redis數據庫,並已啓動好服務。sql

  1) 新建測試工程,修改 pom.xml 配置文件數據庫

 

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 3     <modelVersion>4.0.0</modelVersion>
 4     <groupId>org.viking</groupId>
 5     <artifactId>redis_demo</artifactId>
 6     <packaging>war</packaging>
 7     <version>0.0.1-SNAPSHOT</version>
 8     <name>redis_demo Maven Webapp</name>
 9     <url>http://maven.apache.org</url>
10     <dependencies>
11         <dependency>
12             <groupId>jdk.tools</groupId>
13             <artifactId>jdk.tools</artifactId>
14             <version>1.7</version>
15             <scope>system</scope>
16             <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
17         </dependency>
18         <dependency>
19           <groupId>junit</groupId>
20           <artifactId>junit</artifactId>
21           <version>4.12</version>
22         </dependency>
23         <dependency>
24           <groupId>redis.clients</groupId>
25           <artifactId>jedis</artifactId>
26           <version>2.8.0</version>
27         </dependency>
28         <dependency>
29           <groupId>commons-pool</groupId>
30           <artifactId>commons-pool</artifactId>
31           <version>1.6</version>
32         </dependency>
33     </dependencies>
34     <build>
35         <finalName>${project.artifactId}</finalName>
36         <plugins>
37             <plugin>
38                 <groupId>org.apache.maven.plugins</groupId>
39                 <artifactId>maven-compiler-plugin</artifactId>
40                 <version>2.3.2</version>
41                 <configuration>
42                     <source>${java-version}</source>
43                     <target>${java-version}</target>
44                     <encoding>utf8</encoding>
45                 </configuration>
46             </plugin>
47         </plugins>
48     </build>
49 </project>

 

  2) 建立 RedisUtil.java (用來測試Reids鏈接池使用)

 1 package demo;  2 
 3 import redis.clients.jedis.Jedis;  4 import redis.clients.jedis.JedisPool;  5 import redis.clients.jedis.JedisPoolConfig;  6 
 7 public final class RedisUtil {  8 
 9 //Redis服務器IP
10 private static String ADDR = "127.0.0.1"; 11 
12 //Redis的端口號
13 private static int PORT = 6379; 14 
15 //訪問密碼 16 //private static String AUTH = "admin"; 17 
18 //可用鏈接實例的最大數目,默認值爲8; 19 //若是賦值爲-1,則表示不限制;若是pool已經分配了maxActive個jedis實例,則此時pool的狀態爲exhausted(耗盡)。
20 private static int MAX_ACTIVE = 1024; 21 
22 //控制一個pool最多有多少個狀態爲idle(空閒的)的jedis實例,默認值也是8。
23 private static int MAX_IDLE = 200; 24 
25 //等待可用鏈接的最大時間,單位毫秒,默認值爲-1,表示永不超時。若是超過等待時間,則直接拋出JedisConnectionException;
26 private static int MAX_WAIT = 10000; 27 
28 private static int TIMEOUT = 10000; 29 
30 //在borrow一個jedis實例時,是否提早進行validate操做;若是爲true,則獲得的jedis實例均是可用的;
31 private static boolean TEST_ON_BORROW = true; 32 
33 private static JedisPool jedisPool = null; 34 
35 /**
36  * 初始化Redis鏈接池 37  */
38 static { 39 try { 40 JedisPoolConfig config = new JedisPoolConfig(); 41 config.setMaxIdle(MAX_ACTIVE); 42 //change "maxActive" -> "maxTotal" and "maxWait" -> "maxWaitMillis" in all examples.
43 config.setMaxTotal(MAX_ACTIVE); 44 config.setMaxIdle(MAX_IDLE); 45 config.setMaxWaitMillis(MAX_WAIT); 46 config.setTestOnBorrow(TEST_ON_BORROW); 47 jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT); 48 } catch (Exception e) { 49 e.printStackTrace(); 50 } 51 } 52 
53 /**
54  * 獲取Jedis實例 55  * @return
56  */
57 public synchronized static Jedis getJedis() { 58 try { 59 if (jedisPool != null) { 60 Jedis resource = jedisPool.getResource(); 61 return resource; 62 } else { 63 return null; 64 } 65 } catch (Exception e) { 66 e.printStackTrace(); 67 return null; 68 } 69 } 70 
71 /**
72  * 釋放jedis資源 73  * @param jedis 74  */
75 public static void returnResource(final Jedis jedis) { 76 if (jedis != null) { 77 jedisPool.returnResource(jedis); 78 } 79 } 80 }

  3) 建立 TestRedis.java

 1 package demo;  2 
 3 import java.util.HashMap;  4 import java.util.Iterator;  5 import java.util.List;  6 import java.util.Map;  7 import org.junit.Before;  8 import org.junit.Test;  9 import redis.clients.jedis.Jedis;  10 
 11 public class TestRedis {  12     private Jedis jedis;  13 
 14 @Before  15 public void setup() {  16 //鏈接redis服務器
 17 jedis = new Jedis("127.0.0.1", 6379);  18 }  19 
 20 /**
 21  * redis存儲字符串  22  */
 23 @Test  24 public void testString() {  25 //-----添加數據---------- 
 26 jedis.set("name","yuanxj");//向key-->name中放入了value-->yuanxj 
 27 System.out.println(jedis.get("name"));//執行結果:yuanxj 
 28 
 29 jedis.append("name", " is Fraud"); //拼接
 30 System.out.println(jedis.get("name"));  31 
 32 jedis.del("name");  //刪除某個鍵
 33 System.out.println(jedis.get("name"));  34 //設置多個鍵值對
 35 jedis.mset("name","Viking","age","30","qq","1001");  36 jedis.incr("age"); //進行加1操做
 37 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));  38 
 39 }  40 
 41 /**
 42  * redis操做Map  43  */
 44 @Test  45 public void testMap() {  46 //-----添加數據---------- 
 47 Map<String, String> map = new HashMap<String, String>();  48 map.put("name", "yuanxj");  49 map.put("age", "30");  50 map.put("qq", "1001");  51 jedis.hmset("user1",map);  52 //第一個參數是存入redis中map對象的key,後面跟的是放入map中的對象的key,後面的key能夠跟多個,是可變參數 
 53 List<String> rsmap = jedis.hmget("user1", "name", "age", "qq");  54 System.out.println(rsmap);  55   
 56 //刪除map中的某個鍵值 
 57 jedis.hdel("user1","age");  58 System.out.println(jedis.hmget("user1", "age")); //由於刪除了,因此返回的是null 
 59 System.out.println(jedis.hlen("user1")); //返回key爲user的鍵中存放的值的個數2 
 60 System.out.println(jedis.exists("user1"));//是否存在key爲user的記錄 返回true 
 61 System.out.println(jedis.hkeys("user1"));//返回map對象中的全部key 
 62 System.out.println(jedis.hvals("user1"));//返回map對象中的全部value 
 63   
 64 Iterator<String> iter=jedis.hkeys("user1").iterator();  65 while (iter.hasNext()){  66 String key = iter.next();  67 System.out.println(key+":"+jedis.hmget("user1",key));  68 }  69 }  70 
 71 /** 
 72  * jedis操做List  73  */  
 74 @Test  75 public void testList(){  76 //開始前,先移除全部的內容 
 77 jedis.del("java framework");  78 System.out.println(jedis.lrange("java framework",0,-1));  79 //先向key java framework中存放三條數據 
 80 jedis.lpush("java framework","spring");  81 jedis.lpush("java framework","struts");  82 jedis.lpush("java framework","hibernate");  83 //再取出全部數據jedis.lrange是按範圍取出,  84 // 第一個是key,第二個是起始位置,第三個是結束位置,jedis.llen獲取長度 -1表示取得全部 
 85 System.out.println(jedis.lrange("java framework",0,-1));  86 
 87 jedis.del("java framework");  88 jedis.rpush("java framework","spring");  89 jedis.rpush("java framework","struts");  90 jedis.rpush("java framework","hibernate");  91 System.out.println(jedis.lrange("java framework",0,-1));  92 }  93 
 94 /** 
 95  * jedis操做Set  96  */  
 97 @Test  98 public void testSet(){  99 //添加 
100 jedis.sadd("user2","yuanxj"); 101 jedis.sadd("user2","Fraud"); 102 jedis.sadd("user2","Viking"); 103 jedis.sadd("user2","Jake"); 104 jedis.sadd("user2","who"); 105 //移除noname 
106 jedis.srem("user2","who"); 107 System.out.println(jedis.smembers("user2"));//獲取全部加入的value 
108 System.out.println(jedis.sismember("user2", "who"));//判斷 who 是不是user集合的元素 
109 System.out.println(jedis.srandmember("user2")); 110 System.out.println(jedis.scard("user2"));//返回集合的元素個數 
111 } 112   
113 @Test 114 public void test() throws InterruptedException { 115 //jedis 排序 116 //注意,此處的rpush和lpush是List的操做。是一個雙向鏈表(但從表現來看的) 
117 jedis.del("a");//先清除數據,再加入數據進行測試 
118 jedis.rpush("a", "1"); 119 jedis.lpush("a","6"); 120 jedis.lpush("a","3"); 121 jedis.lpush("a","9"); 122 System.out.println(jedis.lrange("a",0,-1));// [9, 3, 6, 1] 
123 System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //輸入排序後結果 
124 System.out.println(jedis.lrange("a",0,-1)); 125 } 126 
127 @Test 128 public void testRedisPool() { 129 RedisUtil.getJedis().set("newname", "中文測試"); 130 System.out.println(RedisUtil.getJedis().get("newname")); 131 } 132 }

  4) 測試運行結果

  Run as Junit Test  -> See the result!

 

4 Redis之java操做篇(數據對象的存取)

  摘要:Redis自己沒有存取對象的功能,而是有存取byte數據的功能,咱們能夠對要存取的對象進行序列化後,進行操做.

  建立SerializeUtil.java

 1 public class SerializeUtil {  2 /**
 3  * 序列化  4  * @param object  5  */
 6 public static byte[] serialize(Object object) {  7 ObjectOutputStream oos = null;  8 ByteArrayOutputStream baos = null;  9 try { 10 // 序列化
11 baos = new ByteArrayOutputStream(); 12 oos = new ObjectOutputStream(baos); 13 oos.writeObject(object); 14 byte[] bytes = baos.toByteArray(); 15 return bytes; 16 } catch (Exception e) { 17  e.printStackTrace(); 18 } 19 return null; 20 } 21 
22 /**
23  * 反序列化 24  * @param bytes 25  */
26 public static Object unserialize(byte[] bytes) { 27 ByteArrayInputStream bais = null; 28 try { 29 // 反序列化
30 bais = new ByteArrayInputStream(bytes); 31 ObjectInputStream ois = new ObjectInputStream(bais); 32 return ois.readObject(); 33 } catch (Exception e) { 34  e.printStackTrace(); 35 } 36 return null; 37 } 38 }

  1) 新建測試對象

 1 package demo.bean;  2 
 3 import java.io.Serializable;  4 
 5 public class Goods implements Serializable {  6     /**
 7  *  8      */
 9     private static final long serialVersionUID = 6856239042967045162L; 10     private String name; 11     private Float price; 12     private String desc; 13     public String getName() { 14         return name; 15  } 16     public void setName(String name) { 17         this.name = name; 18  } 19     public Float getPrice() { 20         return price; 21  } 22     public void setPrice(Float price) { 23         this.price = price; 24  } 25     public String getDesc() { 26         return desc; 27  } 28     public void setDesc(String desc) { 29         this.desc = desc; 30  } 31     
32 }

  2) 新建測試代碼

 1 package demo;  2 
 3 import demo.bean.Goods;  4 
 5 public class TestObject {  6     public static void main (String[] args) {  7         Goods g1 = new Goods();  8         g1.setName("蘋果");  9  g1.setPrice(5f); 10         g1.setDesc("這裏的蘋果大又甜"); 11         
12         Goods g2 = new Goods(); 13         g2.setName("橘子"); 14         g2.setPrice(3.5f); 15         g2.setDesc("這裏的橘子水不少"); 16         
17         RedisUtil.getJedis().set("g1".getBytes(), SerializeUtil.serialize(g1)); 18         byte[] bg1 = RedisUtil.getJedis().get("g1".getBytes()); 19         Goods rg1 = (Goods)SerializeUtil.unserialize(bg1); 20  System.out.println(rg1.getName()); 21  System.out.println(rg1.getPrice()); 22  System.out.println(rg1.getDesc()); 23  } 24 }

  5 使用mybatis-redis

  mybatis-redis是mybatis集成redis實現二級緩存的一個實現,和mybatis-memcached相似,這種方式是mybatis集成redis最快的方式,無需本身編寫代碼實現cache接口
  mybatis-redis的官方git地址https://github.com/mybatis/redis-cache
  項目集成mybatis-redis

 1 <dependency>
 2 <groupId>org.mybatis.caches</groupId>
 3 <artifactId>mybatis-redis</artifactId>
 4 <version>1.0.0-beta2</version>
 5 </dependency>
 6 <dependency>
 7 <groupId>redis.clients</groupId>
 8 <artifactId>jedis</artifactId>
 9 <version>2.8.0</version>
10 </dependency>

  在mybatis配置中開啓緩存

 1 <setting name="cacheEnabled" value="true"/>
 2 <?xml version="1.0" encoding="UTF-8" ?>
 3 <!DOCTYPE configuration  4  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  5  "http://mybatis.org/dtd/mybatis-3-config.dtd">
 6 <configuration>
 7     <settings>
 8         <setting name="cacheEnabled" value="true"/>
 9         <!--<setting name="lazyLoadingEnabled" value="false"/>-->
10         <!--<setting name="aggressiveLazyLoading" value="true"/>-->
11     </settings>
12     <plugins>
13         <!--mybatis 分頁插件-->
14         <plugin interceptor="com.github.pagehelper.PageHelper">
15             <property name="dialect" value="mysql" />
16         </plugin>
17     </plugins>
18 </configuration>

  在項目的資源(maven resource)目錄中加入redis.propertis文件

1 host=localhost

 2 port=6379    

3 timeout=5000   

  最後在mapper映射文件中開啓cache便可

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 3 <mapper namespace="com.lisi.test.dao.UserDao">
 4 <!--啓用mybatis-redis-->
 5 <cache type="org.mybatis.caches.redis.RedisCache"/>
 6 <resultMap type="User" id="UserResult">
 7 <result property="id" column="id"/>
 8 <result property="uuid" column="uuid"/>
 9 <result property="username" column="username"/>
10 <result property="password" column="password"/>
11 <result property="createTime" column="create_time"/>
12 </resultMap>
13 <insert id="save" parameterType="User">
14 <selectKey resultType="int" keyProperty="id" order="AFTER">
15 SELECT LAST_INSERT_ID() 16 </selectKey>
17 insert into 18 t_user(uuid,username,password,create_time) 19 values(#{uuid},#{username},#{password},#{createTime}) 20 </insert>
21   
22 <delete id="delete" parameterType="long">
23  delete from t_user where id = 24  #{id} 25     </delete>
26    
27 <select id="getById" parameterType="long" resultType="User">
28  select 29  id,uuid,username,password,create_time as createTime from t_user 30  where id=#{id} 31     </select>
32   
33 <update id="update" parameterType="User">
34  update t_user set 35  username=#{username} 36  where id = #{id} 37     </update>
38 </mapper>

6 使用spring-data-redis

  spring-data-redis是比較有名的項目,相關資料不少。
  使用spring-data-redis的關鍵依賴,由於用到spring,因此spring的相關依賴是須要加入的。

 1 <dependency>
 2 <groupId>redis.clients</groupId>
 3 <artifactId>jedis</artifactId>
 4 <version>2.8.0</version>
 5 </dependency>
 6 <dependency>
 7 <groupId>org.springframework.data</groupId>
 8 <artifactId>spring-data-redis</artifactId>
 9 <version>1.7.2.RELEASE</version>
10 </dependency>

  mybatis使用spring-data-redis集成redis緩存和第一種方式很類似,都須要本身實現cache接口,只是使用spring-data-redis後方便使用spring的方式來管理,

  代碼:

 1 /**  2  * Use JedisConnectionFactory  3  */  4 public class SpringRedisCache implements Cache {  5 private static Logger logger = LoggerFactory.getLogger(SpringRedisCache.class);  6 
 7 private JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory)SpringContextHolder.getBean("jedisConnectionFactory");  8 private final String id;  9 
 10 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  11 
 12 public SpringRedisCache(final String id) {  13 if (id == null) {  14 throw new IllegalArgumentException("Cache instances require an ID");  15 }  16 logger.debug("SpringRedisCache:id=" + id);  17 this.id = id;  18 }  19 
 20 @Override  21 public void clear() {  22 RedisConnection connection = null;  23 try {  24 connection = jedisConnectionFactory.getConnection();  25 connection.flushDb();  26 connection.flushAll();  27 } catch (JedisConnectionException e) {  28 e.printStackTrace();  29 } finally {  30 if (connection != null) {  31 connection.close();  32 }  33 }  34 }  35 
 36 @Override  37 public String getId() {  38 return this.id;  39 }  40 
 41 @Override  42 public Object getObject(Object key) {  43 Object result = null;  44 RedisConnection connection = null;  45 try {  46 connection = jedisConnectionFactory.getConnection();  47 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();  48 result = serializer.deserialize(connection.get(serializer.serialize(key)));  49 } catch (JedisConnectionException e) {  50 e.printStackTrace();  51 } finally {  52 if (connection != null) {  53 connection.close();  54 }  55 }  56 return result;  57 }  58 
 59 @Override  60 public ReadWriteLock getReadWriteLock() {  61 return this.readWriteLock;  62 }  63 
 64 @Override  65 public int getSize() {  66 int result = 0;  67 RedisConnection connection = null;  68 try {  69 connection = jedisConnectionFactory.getConnection();  70 result = Integer.valueOf(connection.dbSize().toString());  71 } catch (JedisConnectionException e) {  72 e.printStackTrace();  73 } finally {  74 if (connection != null) {  75 connection.close();  76 }  77 }  78 return result;  79 }  80 
 81 @Override  82 public void putObject(Object key, Object value) {  83 RedisConnection connection = null;  84 try {  85 connection = jedisConnectionFactory.getConnection();  86 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();  87 connection.set(serializer.serialize(key), serializer.serialize(value));  88 } catch (JedisConnectionException e) {  89 e.printStackTrace();  90 } finally {  91 if (connection != null) {  92 connection.close();  93 }  94 }  95 }  96 
 97 @Override  98 public Object removeObject(Object key) {  99 RedisConnection connection = null; 100 Object result = null; 101 try { 102 connection = jedisConnectionFactory.getConnection(); 103 RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); 104 result = connection.expire(serializer.serialize(key), 0); 105 } catch (JedisConnectionException e) { 106 e.printStackTrace(); 107 } finally { 108 if (connection != null) { 109 connection.close(); 110 } 111 } 112 return result; 113 } 114 }

  上面使用的SpringContextHolder源碼

 1 @Component  2 public class SpringContextHolder implements ApplicationContextAware {  3 private static ApplicationContext context;  4 
 5 @Override  6 public void setApplicationContext(ApplicationContext context)  7 throws BeansException {  8 SpringContextHolder.context = context;  9 } 10 public static <T> T getBean(String name){ 11 return (T)context.getBean(name); 12 } 13 }

  在項目的資源(maven resource)目錄中加入redis.propertis文件

1 redis.host=localhost 2 redis.port=6379 3 redis.pass= 4 redis.timeout=5000 5 redis.default.db=0 6 redis.maxIdle=300 7 redis.maxActive=600 8 redis.maxWait=1000 9 redis.testOnBorrow=true

  在spring中配置加入

 1  <!-- redis數據池配置 -->
 2 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
 3 <property name="maxIdle" value="${redis.maxIdle}" />
 4 <property name="maxTotal" value="${redis.maxActive}" />
 5 <property name="maxWaitMillis" value="${redis.maxWait}" />
 6 <property name="testOnBorrow" value="${redis.testOnBorrow}" />
 7 </bean>
 8 <!-- Spring-data-redis connectFactory -->
 9 <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
10 <property name="usePool" value="true"></property>
11 <property name="hostName" value="${redis.host}" />
12 <property name="port" value="${redis.port}" />
13 <property name="password" value="${redis.pass}" />
14 <property name="timeout" value="${redis.timeout}" />
15 <property name="database" value="${redis.default.db}"/>
16 <constructor-arg index="0" ref="jedisPoolConfig" />
17 </bean>

  最後修改mapper文件中cache的type爲SpringRedisCache便可;

  使用spring-data-redis還可使用它的RedisTemplate去實現cache接口,不過由於RedisTemplate是對JedisConnectionFactory的包裝,在spring配置文件的配置更多.

 

<!-- Start -->

獲知及時信息,請關注個人我的微信訂閱號:0與1的那點事

 

<!-- End -->

 

本文爲博主原創文章,轉載請註明出處!

http://www.cnblogs.com/libingbin/

感謝您的閱讀。

相關文章
相關標籤/搜索