properties文件配置
#配置连接池属性
#连接池最小空闲连接数
spring.redis.jedis.pool.min-idle=5
#连接池最大空闲连接数
spring.redis.jedis.pool.max-idle=10
#连接池最大连接数
spring.redis.jedis.pool.max-active=10
#连接池最大阻塞等待时间
spring.redis.jedis.pool.max-wait=2000
#配置redis服务器属性
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.timeout=1000
springboot通过自动装配机制读取配置文件,生成有关的redis操作对象,自动生产RedisConnectionFactory,RedisTemplate,stringRedisTemplate。
RedisTemplate会默认使用JdkSerializationRedisSerializer对键值对进行序列化操作,这样便能存储到Redis服务器中。
RedisTemplate中的序列化器属性
有时候我们需要连续操作一个散列数据类型或者列表多长,这时Spring也提供支持,它提供了对应的BoundXXXOperations接口。
SessionCallback和RedisCallback接口,它们的作用是让RedisTemplate进行回调,通过他们可以在同一条连接下执行多个Redis命令。其中SessionCallback提供了良好的封装,对于开发者比较友好,
因此在实际开发中优先选择使用它,相对而言,RedisCallback接口比较底层层次,需要处理的内容比较多,可读性较差,所以在必要的时候尽量不选择使用它。
1.修改RedisTemplate序列化器
@Configuration
public class RedisConfig {
@Autowired
private RedisTemplate redisTemplate;
@PostConstruct
public void init(){
initRedisTemplate();
}
private void initRedisTemplate(){
RedisSerializer redisSerializer = redisTemplate.getStringSerializer();
//对RedisTemplate的默认序列化进行修改
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
}
}
2.4中数据类型的用法
@Controller
@RequestMapping("/redis")
public class RedisController {
private static final Logger logger = LoggerFactory.getLogger(RedisController.class);
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/string")
@ResponseBody
public Map<String,Object> testStringAndHash(){
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();
// //减1操作,这个命令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 hashOperations = stringRedisTemplate.boundHashOps("hash");
//删除两个字段
hashOperations.delete("field1","field2");
//新增一个字段
hashOperations.put("filed4","value5");
return null;
}
@RequestMapping("/list")
@ResponseBody
public String testList(){
//插入两个列表,它们在链表的顺序
//链表从左到右顺序为v10-v2
stringRedisTemplate.opsForList().leftPushAll("list1","v2","v4","v6","v8","v10");
//链表从左到右顺序为v1-v6
stringRedisTemplate.opsForList().rightPushAll("list2","v1","v2","v3","v4","v5","v6");
stringRedisTemplate.opsForList().rightPushAll("list3","v1","v2");
stringRedisTemplate.opsForList().rightPushAll("list4","v1","v2","V3");
BoundListOperations listOps = stringRedisTemplate.boundListOps("list4");
//从右边弹出一个成员
Object result1 = listOps.rightPop();
logger.info(result1.toString());
//获取定位元素,redis从0开始计算,这里的值为v2
Object result2 = listOps.index(1);
logger.info(result2.toString());
//从左边插入链表
listOps.leftPush("v0");
//链表长度
Long size = listOps.size();
logger.info(size.toString());
//链表下标区间成员,整个链表下标范围为0到size-1,这里不取最后一个元素
List elements = listOps.range(0, size-2);
logger.info(elements.toString());
return "";
}
@RequestMapping("/set")
@ResponseBody
public String testSet(){
//这里v1重复两次,集合中不允许重复,所以只插入5个成员到集合中
stringRedisTemplate.opsForSet().add("set1","v1","v1","v2","v3","v4","v5");
stringRedisTemplate.opsForSet().add("set2","v2","v4","v6","v8");
BoundSetOperations setOps = stringRedisTemplate.boundSetOps("set1");
//增加两个元素
setOps.add("v6","v7");
//删除元素
setOps.remove("v1","v7");
//返回所有元素
Set set1 = setOps.members();
//集合大小
Long size = setOps.size();
//求交集,set1和set2中的重复元素
Set inter = setOps.intersect("set2");
//求交集,并且用新的集合inter保存
setOps.intersectAndStore("set2","inter");
//求差集
Set diff = setOps.diff("set2");
//求差集,并且用新集合diff保存
setOps.diffAndStore("set2","diff");
//求并集
Set union = setOps.union("set2");
//求并集,并且用新的集合union保存
setOps.unionAndStore("set2","union");
return null;
}
@RequestMapping("/zset")
@ResponseBody
public String testZset(){
Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
for(int i=1; i<=9; i++){
//分数
double score = i * 0.1;
ZSetOperations.TypedTuple<String> typedTuple
=new DefaultTypedTuple<>("value" + i, score);
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> setScore = zsetOps.rangeByScore(0.2,0.6);
//定义值范围
Range range = new 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>> rangSet = zsetOps.rangeWithScores(1,6);
//在分数区间下,按分数排序,同时返回value和score
Set<ZSetOperations.TypedTuple<String>> scoreSet = zsetOps.rangeByScoreWithScores(1,6);
//按从小到大排序
Set<String> reverseSet = zsetOps.reverseRange(2,8);
return "";
}
}
使用Redis事务
Redis是支持一定事务的能力的NoSQL,在Redis中使用事务,通常的命令组合是watch...multi...exec,也就是要在一个Redis连接中执行多个命令,这时候可以使用SessionCallback接口。其中
watch命令是可以监控Redis的一些键;multi命令是开始事务,开始事务后,客户端的命令不会马上被执行,而是存放在一个队列里面,也就是在这时我们执行一些返回数据的命令,Redis也是不会马上执行的,
而是把命令放到一个队列里面,所以此时调用Redis的命令,结果都是返回null;exec命令的意义在于执行事务,只是它在队列命令执行前会判断watch监控的Redis的键的数据是否发生过变化,如果发生变化
Redis就会取消事务,否则就会执行事务,Redis在执行事务时,要么全部执行,要么全部不执行,而且不会被其他客户端打断,这样就保证了Redis事务下数据的一致性。
@RequestMapping("multi")
@ResponseBody
public String testMulti(){
redisTemplate.opsForValue().set("key1","value1");
List list = (List)redisTemplate.execute((RedisOperations operations)->{
//设置要监控key1
operations.watch("key1");
//开启事务,在exec命令执行前,全部都只是进入队列
operations.multi();
operations.opsForValue().set("key2","value2");
//获取值将为null,因为reids只是把命令放入队列
Object value2 = operations.opsForValue().get("key2");
System.out.println("命令在队列,所以value为null【"+value2+"】");
operations.opsForValue().set("key3","value3");
Object value3 = operations.opsForValue().get("key3");
System.out.println("命令在队列,所以value为null【"+value3+"】");
//执行exec命令,将现判断key1是否在监控后被修改过,如果是则不执行事务,否则就执行事务
return operations.exec();
});
System.out.println(list);
return "";
}
redis发布订阅