Redis 安裝與SpringBoot整合

1.前言

       Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。我們都知道,在日常的應用中,數據庫瓶頸是最容易出現的。數據量太大和頻繁的查詢,由於磁盤IO性能的侷限性,導致項目的性能越來越低。這時候,基於內存的緩存框架,就能解決我們很多問題。例如Memcache,Redis等。將一些頻繁使用的數據放入緩存讀取,大大降低了數據庫的負擔。提升了系統的性能。

      有於Memcached,對於緩存對象大小有要求,單個對象不得大於1MB,且不支持複雜的數據類型,譬如SET等。因此現在Redis用的越來越多。

 

2.Redis 的單機版

  • 安裝步驟:

第一步:安裝gcc編譯環境

yum install gcc-c++

第二步:把redis的源碼上傳到linux服務器。

第三步:解壓縮。

tar -zxvf redis-3.0.0.tar.gz

第四步:make

第五步:make install PREFIX=/usr/local/redis

 

  • 啓動redis

兩種啓動方式,前端啓動、後臺啓動。

前端啓動:./redis-server

後臺啓動:

  1. 複製redis.conf到redis的安裝目錄
  2. 修改redis.conf。修改daemonize yes
  3. [root@bogon redis]# ./redis-server redis.conf

 

  • 客戶端

redis-cli -p 端口 -h ip地址 <-c>連接集羣時使用此參數

 

默認端口:6379

Ip:localhost(127.0.0.1)

 

RedisDesktopManager:

只能在單機版環境使用。不支持redis集羣。

 

3.Redis集羣

  • redis-cluster架構圖

架構細節:

(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.

(2)節點的fail是通過集羣中超過半數的節點檢測失效時才生效.

(3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可

(4)redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value

Redis 集羣中內置了 16384 個哈希槽,當需要在 Redis 集羣中放置一個 key-value 時,redis 先對 key 使用 crc16 算法算出一個結果,然後把結果對 16384 求餘數,這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大致均等的將哈希槽映射到不同的節點

 

  • 集羣搭建

集羣中應該至少有三個節點,每個節點有一備份節點。需要6臺服務器。

搭建僞分佈式,需要6個redis實例。

搭建集羣的步驟:

第一步:創建6個redis實例指定端口從7001到7006

第二步:修改redis.conf 打開Cluster-enable yes前面的註釋。

第三步:需要一個ruby腳本。在redis源碼文件夾下的src目錄下。redis-trib.rb

第四步:把redis-trib.rb文件複製到到redis-cluster目錄下。

第五步:執行ruby腳本之前,需要安裝ruby環境。

1、yum install ruby

2、yum install rubygems

3、安裝redis-trib.rb運行依賴的ruby的包。

[root@bogon ~]# gem install redis-3.0.0.gem

第六步:啓動所有的redis實例。

第七步:使用redis-trib.rb創建集羣。

./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005  192.168.25.153:7006

使用客戶端連接集羣: redis01/redis-cli -p 7001 -c

4.傳統spring配置

redis.properties

redis.host=192.168.1.30
redis.port=6379

redis.password=123456x
redis.timeout=60000

redis.maxIdle=10
redis.maxTotal=100
redis.maxWaitMillis=60000
redis.testOnBorrow=true
redis.testOnReturn=true
redis.testWhileIdle=true

applicationContext-redis.xml

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<context:property-placeholder location="classpath*:redis.properties"
		ignore-unresolvable="true" />

	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxTotal" value="${redis.maxTotal}" />
		<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
		<property name="testOnReturn" value="${redis.testOnReturn}" />
		<property name="testWhileIdle" value="${redis.testWhileIdle}" />
	</bean>

	<bean id="jeidsConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<!-- <constructor-arg ref="redisSentinelConfiguration" /> -->
		<property name="hostName" value="${redis.host}"></property>
		<property name="port" value="${redis.port}"></property>
		<property name="password" value="${redis.password}"></property>
		<property name="timeout" value="${redis.timeout}"></property>
		<property name="poolConfig" ref="jedisPoolConfig"></property>
	</bean>

	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jeidsConnectionFactory" />
		
	<bean id="redisCacheHandler" class="com.palmboo.cache.redis.RedisCacheHandler"/>

</beans>

pom.xml

        <!-- jedis依賴 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.6.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.1.0</version>
        </dependency>

RedisTest.java

package cn.qlq.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.qlq.util.RedisUtil;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-*.xml")
@SuppressWarnings("all")
public class RedisTest {
    @Autowired
    private RedisUtil redisUtil;
    @Resource(name="redisTemplate")
    private RedisTemplate redisTemplate;

    @Test
    public void testSpringRedis() {
        // stringRedisTemplate的操作
        // String讀寫
        redisTemplate.delete("myStr");
        redisTemplate.opsForValue().set("myStr", "skyLine");
        System.out.println(redisTemplate.opsForValue().get("myStr"));
        System.out.println("---------------");

        // List讀寫
        redisTemplate.delete("myList");
        redisTemplate.opsForList().rightPush("myList", "T");
        redisTemplate.opsForList().rightPush("myList", "L");
        redisTemplate.opsForList().leftPush("myList", "A");
        List<String> listCache = redisTemplate.opsForList().range("myList", 0, -1);
        for (String s : listCache) {
            System.out.println(s);
        }
        System.out.println("---------------");

        // Set讀寫
        redisTemplate.delete("mySet");
        redisTemplate.opsForSet().add("mySet", "A");
        redisTemplate.opsForSet().add("mySet", "B");
        redisTemplate.opsForSet().add("mySet", "C");
        Set<String> setCache = redisTemplate.opsForSet().members("mySet");
        for (String s : setCache) {
            System.out.println(s);
        }
        System.out.println("---------------");

        // Hash讀寫
        redisTemplate.delete("myHash");
        redisTemplate.opsForHash().put("myHash", "BJ", "北京");
        redisTemplate.opsForHash().put("myHash", "SH", "上海");
        redisTemplate.opsForHash().put("myHash", "HN", "河南");
        Map<String, String> hashCache = redisTemplate.opsForHash().entries("myHash");
        for (Map.Entry entry : hashCache.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }
        System.out.println("---------------");
    }
    
}

5.SpringBoot配置連接Redis

在配置文件application.properties中添加redis的連接配置信息

# Redis數據庫索引(默認爲0)  
spring.redis.database=0  
# Redis服務器地址  
spring.redis.host=localhost
# Redis服務器連接端口  
spring.redis.port=6379  
# Redis服務器連接密碼
spring.redis.password=neuai-iot-redis
# 連接池最大連接數(使用負值表示沒有限制)  
spring.redis.pool.max-active=200
# 連接池最大阻塞等待時間(使用負值表示沒有限制)  
spring.redis.pool.max-wait=-1
# 連接池中的最大空閒連接  
spring.redis.pool.max-idle=10
# 連接池中的最小空閒連接  
spring.redis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000

1、添加引用

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.49</version>
</dependency>

2、添加自定義序列化器,這裏使用fastjson

package com.example.springbootredis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.Charset;

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class<T> clazz;

    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (null == t) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (null == bytes || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (T) JSON.parseObject(str, clazz);
    }
}

3、添加RedisConfig配置

package com.example.springbootredis;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();

        //使用fastjson序列化
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        // value值的序列化採用fastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化採用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

 4、測試使用 


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class IndexController {

	@Autowired
	private StringRedisTemplate template;

	/**
	 * 根據key值從Redis緩存取得數據
	 * 
	 * @param key
	 * @return
	 */
	@RequestMapping("/redis/get/{key}")
	private String get(@PathVariable("key") String key) {
		// 返回緩存中的數據
		return template.opsForValue().get(key);
	}

	/**
	 * 設置數據到Redis緩存中
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	@RequestMapping("/redis/set/{key}/{value}")
	private Boolean set(@PathVariable("key") String key, @PathVariable("value") String value) {
		boolean flag = true;
		try {
			// 設置緩存中的數據
			template.opsForValue().set(key, value);
		} catch (Exception e) {
			e.printStackTrace();
			flag = false;
		}
		return flag;
	}

}

 5、Redis連接通用類

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

/**
 * spring redis 工具類
 * 
 **/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{
    @Autowired
    public RedisTemplate redisTemplate;

    /**
     * 緩存基本的對象,Integer、String、實體類等
     *
     * @param key 緩存的鍵值
     * @param value 緩存的值
     * @return 緩存的對象
     */
    public <T> ValueOperations<String, T> setCacheObject(String key, T value)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value);
        return operation;
    }

    /**
     * 緩存基本的對象,Integer、String、實體類等
     *
     * @param key 緩存的鍵值
     * @param value 緩存的值
     * @param timeout 時間
     * @param timeUnit 時間顆粒度
     * @return 緩存的對象
     */
    public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value, timeout, timeUnit);
        return operation;
    }

    /**
     * 獲得緩存的基本對象。
     *
     * @param key 緩存鍵值
     * @return 緩存鍵值對應的數據
     */
    public <T> T getCacheObject(String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 刪除單個對象
     *
     * @param key
     */
    public void deleteObject(String key)
    {
        redisTemplate.delete(key);
    }

    /**
     * 刪除集合對象
     *
     * @param collection
     */
    public void deleteObject(Collection collection)
    {
        redisTemplate.delete(collection);
    }

    /**
     * 緩存List數據
     *
     * @param key 緩存的鍵值
     * @param dataList 待緩存的List數據
     * @return 緩存的對象
     */
    public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList)
    {
        ListOperations listOperation = redisTemplate.opsForList();
        if (null != dataList)
        {
            int size = dataList.size();
            for (int i = 0; i < size; i++)
            {
                listOperation.leftPush(key, dataList.get(i));
            }
        }
        return listOperation;
    }

    /**
     * 獲得緩存的list對象
     *
     * @param key 緩存的鍵值
     * @return 緩存鍵值對應的數據
     */
    public <T> List<T> getCacheList(String key)
    {
        List<T> dataList = new ArrayList<T>();
        ListOperations<String, T> listOperation = redisTemplate.opsForList();
        Long size = listOperation.size(key);

        for (int i = 0; i < size; i++)
        {
            dataList.add(listOperation.index(key, i));
        }
        return dataList;
    }

    /**
     * 緩存Set
     *
     * @param key 緩存鍵值
     * @param dataSet 緩存的數據
     * @return 緩存數據的對象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet)
    {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 獲得緩存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(String key)
    {
        Set<T> dataSet = new HashSet<T>();
        BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
        dataSet = operation.members();
        return dataSet;
    }

    /**
     * 緩存Map
     *
     * @param key
     * @param dataMap
     * @return
     */
    public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap)
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        if (null != dataMap)
        {
            for (Map.Entry<String, T> entry : dataMap.entrySet())
            {
                hashOperations.put(key, entry.getKey(), entry.getValue());
            }
        }
        return hashOperations;
    }

    /**
     * 獲得緩存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(String key)
    {
        Map<String, T> map = redisTemplate.opsForHash().entries(key);
        return map;
    }

    /**
     * 獲得緩存的基本對象列表
     * 
     * @param pattern 字符串前綴
     * @return 對象列表
     */
    public Collection<String> keys(String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}

 

發佈了83 篇原創文章 · 獲贊 33 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章