1、pom檔案
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<artifactId>lettuce-core</artifactId>
<groupId>io.lettuce</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
備注: 排除掉 lettuce-core用戶端工具,使用jedis工具
2、java類
RedisConfig.java----->
package fun.huanghai.redis.config;
import fun.huanghai.redis.listener.RedisMessageListener;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisConfig implements ApplicationContextAware{
private ApplicationContext applicationContext;
//任務池
private ThreadPoolTaskScheduler taskScheduler;
@Bean
public RedisConnectionFactory redisConnectionFactory(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxWaitMillis(2000);
poolConfig.setMaxIdle(30);
poolConfig.setMaxTotal(50);
RedisConnectionFactory factory = new JedisConnectionFactory(poolConfig);
return factory;
}
/**
* 配置序列化器
* @param //redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
//RedisTemplate會自動初始化StringRedisSerializer,是以這裡直接擷取
RedisSerializer<String> stringSerializer = redisTemplate.getStringSerializer();
//設定字元串序列化器,這樣Spring就會把Redis的key當做字元串處理了
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
/**
* 建立任務池,運作線程等待處理Redis的消息
* @return
*/
@Bean
public ThreadPoolTaskScheduler taskScheduler(){
if(taskScheduler!=null){
return taskScheduler;
}
taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(20);
return taskScheduler;
}
/**
* redis消息監聽容器
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//redis連接配接工廠
container.setConnectionFactory(redisConnectionFactory);
//設定運作任務
container.setTaskExecutor(taskScheduler);
//定義監聽管道,名稱為topic1
Topic topic = new ChannelTopic("topic1");
//使用監聽器監聽Redis的消息
RedisMessageListener bean = applicationContext.getBean(RedisMessageListener.class);
container.addMessageListener(bean,topic);
return container;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
RedisMessageListener.java----->
package fun.huanghai.redis.listener;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
@Component
public class RedisMessageListener implements MessageListener {
@Override
public void onMessage(Message message, @Nullable byte[] bytes) {
//消息體
String body = new String(message.getBody());
//管道名稱
String topic = new String(bytes);
System.out.println(body);
System.out.println(topic);
}
}
RedisController.java---->
package fun.huanghai.redis.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;
import java.util.*;
@RequestMapping("/redis")
@RestController
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//使用Redis的字元串(string)和哈希(hash)
@GetMapping("/stringAndHash")
public Map<String,Object> testStringAndHash(){
Map<String,Object> map = new HashMap<>();
redisTemplate.opsForValue().set("key1","value1");
//注意這裡使用JDK的序列化器,是以Redis儲存時不是整數,不能運算
redisTemplate.opsForValue().set("int_key","1");
stringRedisTemplate.opsForValue().set("int","1");
//使用運算
stringRedisTemplate.opsForValue().increment("int",1);
//擷取底層Jedis連接配接
Jedis jedis = (Jedis) stringRedisTemplate.getConnectionFactory()
.getConnection()
.getNativeConnection();
//減一操作,這個指令RedisTemplate不支援,是以我先擷取底層的連接配接在操作
jedis.decr("int");
Map<String,String> hash = new HashMap<>();
hash.put("field1","value1");
hash.put("field2","value2");
//存入一個散列資料類型
stringRedisTemplate.opsForHash().putAll("hash",hash);
//新增一個字段
stringRedisTemplate.opsForHash().put("hash","field3","value3");
//綁定散列操作的key,這樣可以連續對同一個散列資料類型進行操作
BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps("hash");
//删除2個字段
hashOps.delete("field1","field2");
//新增一個字段
hashOps.put("field4","value4");
map.put("success",true);
return map;
}
//使用Redis的連結清單(清單)
@RequestMapping("/list")
public Map<String,Object> testList(){
//插入2個清單,注意它們在連結清單的順序
//連結清單從左到右順序為v10,v8,v6,v4,v2
stringRedisTemplate.opsForList().leftPushAll("list1","v2","v4",
"v6","v8","v10");
//連結清單從左到右順序為v1,v2,v3,v4,v5,v6
stringRedisTemplate.opsForList().rightPushAll("list2","v1","v2",
"v3","v4","v5","v6");
//綁定list2連結清單操作
BoundListOperations<String, String> listOps = stringRedisTemplate.boundListOps("list2");
//從右邊彈出一個成員 v1,v2,v3,v4,v5
Object r1 = listOps.rightPop();
//擷取定位元素,Redis從0開始計算,這裡值為v2
Object r2 = listOps.index(1);
//從左邊插傳入連結表 v0,v1,v2,v3,v4,v5
listOps.leftPush("v0");
//求連結清單長度 6
Long size = listOps.size();
//求連結清單下标區間成員,整個連結清單下标範圍為0到size-1,這裡不取最後一個元素 v0,v1,v2,v3,v4
List<String> elements = listOps.range(0, size - 2);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("list",elements);
map.put("r1",r1);
map.put("r2",r2);
map.put("size",size);
return map;
}
//使用Redis的集合
@GetMapping("/set")
public Map<String,Object> testSet(){
//請注意:這裡v1重複2次,因為集合不允許重複,是以隻是插入5個成員到集合中
stringRedisTemplate.opsForSet().add("set1","v1","v1",
"v2","v3","v4","v5");
stringRedisTemplate.opsForSet().add("set2","v2","v4","v6","v8");
//綁定set1集合操作
BoundSetOperations<String, String> setOps = stringRedisTemplate.boundSetOps("set1");
//增加2個元素 v1,v2,v3,v4,v5,v6,v7
setOps.add("v6","v7");
//删除2個元素 v2,v3,v4,v5,v6
setOps.remove("v1","v7");
//傳回所有元素 v2,v3,v4,v5,v6
Set<String> set1 = setOps.members();
//求成員數 5
Long size = setOps.size();
//求交集 v2,v4,v6
Set<String> set2 = setOps.intersect("set2");
//求交集,并且用新集合inter儲存 v2,v4,v6
setOps.intersectAndStore("set2","inter");
//求差集 v3,v5
Set<String> diff = setOps.diff("set2");
//求差集,并且用新集合diff儲存
setOps.diffAndStore("set2","diff");
//求并集 v2,v3,v4,v5,v6,v8
Set<String> union = setOps.union("set2");
//求并集,并且用新集合union儲存
setOps.unionAndStore("set2","union");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("set1",set1);
map.put("size",size);
map.put("inter",set2);
map.put("diff",diff);
map.put("union",union);
return map;
}
//使用Redis的有序結合
@GetMapping("/zset")
public Map<String,Object> testZset(){
Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
for (int i = 0; i < 9; i++) {
//分數
double scope = i*0.1;
//建立一個TypedTuple對象,存入值和分數
ZSetOperations.TypedTuple<String> typedTuple = new DefaultTypedTuple<>("value"+i,scope);
typedTupleSet.add(typedTuple);
}
//往有序結合插入元素
stringRedisTemplate.opsForZSet().add("zset1",typedTupleSet);
//綁定zset1有序結合操作
BoundZSetOperations<String, String> zSetOps = stringRedisTemplate.boundZSetOps("zset1");
//增加一個元素
zSetOps.add("value10",0.26);
Set<String> setRange = zSetOps.range(1, 6);
//按分數排序擷取有序集合
Set<String> setScope = zSetOps.rangeByScore(0.2, 0.6);
//定義值範圍
RedisZSetCommands.Range range = new RedisZSetCommands.Range();
range.gt("value3");//大于value3
//range.gte("value3");//大于等于value3
//range.lt("value8");//小于value8
range.lte("value8");//小于等于value8
//按值排序,請注意這個排序是按字元串排序
Set<String> setLex = zSetOps.rangeByLex(range);
//删除元素
zSetOps.remove("value9","value2");
//求分數
Double score = zSetOps.score("value8");
//在下标區間下,按分數排序,同時傳回value和score
Set<ZSetOperations.TypedTuple<String>> scoreSet = zSetOps.rangeWithScores(1, 6);
//按從大到小排序
Set<String> reverseSet = zSetOps.reverseRange(2, 8);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("setRange",setRange);
map.put("setScope",setScope);
map.put("setLex",setLex);
map.put("scoreSet",scoreSet);
map.put("reverseSet",reverseSet);
map.put("score",score);
return map;
}
//使用Redis流水線測試性能
@RequestMapping("/multi")
public Map<String,Object> testMulti(){
redisTemplate.opsForValue().set("key1","value1");
List list = (List) redisTemplate.execute(new SessionCallback() {
@Nullable
@Override
public Object execute(RedisOperations ro) throws DataAccessException {
//設定要監控的key1
ro.watch("key1");
//開啟事務,在exec指令執行前,全部都隻是進入隊列
ro.multi();;
ro.opsForValue().set("key2","vlue2");
ro.opsForValue().increment("key1",1);
//擷取值将為null,因為redis隻是把指令放入隊列
Object key2 = ro.opsForValue().get("key2");
System.out.println("指令在隊列,是以value為null【"+key2+"】");
ro.opsForValue().set("key3","value3");
Object key3 = ro.opsForValue().get("key3");
System.out.println("指令在隊列,是以value為null【"+key3+"】");
//執行exec指令,将先判别key1是否在監控後被修改過,如果是則不執行事務,否則就執行事務
return ro.exec();
}
});
System.out.println(list);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
return map;
}
//使用Redis流水線測試性能
@RequestMapping("/pipeline")
public Map<String,Object> testPipeline(){
long start = System.currentTimeMillis();
List list = redisTemplate.executePipelined(new SessionCallback<Object>() {
@Nullable
@Override
public Object execute(RedisOperations ro) throws DataAccessException {
for (int i = 0; i < 10000; i++) {
ro.opsForValue().set("pipeline_"+i,"value_"+i);
String value = (String) ro.opsForValue().get("pipeline_"+i);
if(i==10000){
System.out.println("指令隻是進入隊列,是以值為空【"+value+"】");
}
}
return null;
}
});
long end = System.currentTimeMillis();
System.out.println("耗時:"+(end-start)+"毫秒。");
Map<String,Object> map = new HashMap<>();
map.put("success",true);
return map;
}
/**
* 發送消息到redis中(訂閱模式)
* @param body
* @return
*/
@GetMapping("/message")
public Map<String,Object> testMessage(String body){
redisTemplate.convertAndSend("topic1",body);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
return map;
}
//使用lua腳本
@GetMapping("/lua")
public Map<String,Object> testLua(){
DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
//設定腳本
redisScript.setScriptText("return 'Hello Redis'");
//定義傳回類型,注意: 如果沒有這個定義,Spring不會傳回結果
redisScript.setResultType(String.class);
RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
//執行lua腳本
Object obj = redisTemplate.execute(redisScript, stringSerializer, stringSerializer, null);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("res",obj);
return map;
}
//使用lua腳本
@GetMapping("/lua2")
public Map<String,Object> testLua2(String k1,String k2,String v1,String v2){
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
//設定腳本
String lua = "redis.call('set',KEYS[1],ARGV[1])\n" +
"redis.call('set',KEYS[2],ARGV[2])\n" +
"local str1 = redis.call('get',KEYS[1])\n" +
"local str2 = redis.call('get',KEYS[2])\n" +
"if str1 == str2 then\n" +
"return 1\n" +
"end\n" +
"return 0";
redisScript.setScriptText(lua);
//定義傳回類型,注意: 如果沒有這個定義,Spring不會傳回結果
redisScript.setResultType(Long.class);
RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
//定義key參數
List<String> keyList = new ArrayList<>();
keyList.add(k1);
keyList.add(k2);
//傳遞2個參數值,其中第一個序列化器是key的序列化器,第二個序列化器是參數的序列化器
Object obj = redisTemplate.execute(redisScript, stringSerializer, stringSerializer, keyList,v1,v2);
Map<String,Object> map = new HashMap<>();
map.put("success",true);
map.put("res",obj);
return map;
}
}
備注:因為redis預設是連接配接 localhost:6379,是以沒有配置位址和端口号了 (基本常用的redis操作都在這了)