本节目标
- 了解SpringBoot默认支持的两种操作redis的工具包
- 采用lettuce操作redis
- 了解redission
- 采用redission操作redis
本节项目:
- springboot + lettuce/jedis
- springboot + redisson
传统方式操作redis
1.集成lettuce操作redis
1.1 SpringBoot三板斧之添加依赖
xml
代码解读
复制代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
由于我们把spring-boot-dependencies
的pom引入了,所以这个的版本也就定下来。
可以通过Maven Helper的插件来看看这个spring-boot-starter-data-redis
的依赖关系,如下图:
从依赖中可以看到默认依赖的是lettuce的包,这也就是为什么我们经常说spring-boot-starter-data-redis
默认使用的是lettuce。
1.2 SpringBoot三板斧之添加配置
-
单机配置
yaml
代码解读
复制代码
spring: redis: host: 192.168.0.1 port: 6379 password: t+UUVnXZ6cysf3lr/N02d>ly+mwm/1P database: 0 connect-timeout: 10s
-
集群配置
yaml
代码解读
复制代码
spring: redis: cluster: nodes: - 192.168.0.1:6379 - 192.168.0.2:6379 - 192.168.0.3:6379 password: t+UUVnXZ6cysf3lr/N02d>ly+mwm/1P timeout: 10s
1.3 测试reids
typescript
代码解读
复制代码
@SpringBootTest public class RedisTest { @Resource private RedisTemplate<String, Object> redisTemplate; @Test public void testRedisTemplate() { redisTemplate.opsForValue().set("laoma", 55); Object laoma = redisTemplate.opsForValue().get("laoma"); Console.log("laoma:{}", laoma); } }
通过redis的客户端工具也能看到设置值成功了:
但是这里的值,观察的不是很明显,因为在redis操作的时候,采用的序列化是采用默认的jdk序列化对象的方式。也就是类似字节码的形式存储。
1.4 序列化
上面提到了默认采用字节码形式存储,不太便于查看。而我们经常是采用json结构把一个对象存储到redis中,首先看看RedisTemplate这个类中默认的序列化方式,源码如下:
Redis本身提供了一下一种序列化的方式:
- GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
- Jackson2JsonRedisSerializer: 序列化object对象为json字符串
- JdkSerializationRedisSerializer: 序列化java对象
- StringRedisSerializer: 简单的字符串序列化
如果我们存储的是String类型,默认使用的是StringRedisSerializer 这种序列化方式。如果我们存储的是对象,默认使用的是 JdkSerializationRedisSerializer,也就是Jdk的序列化方式(通过ObjectOutputStream和ObjectInputStream实现,缺点是我们无法直观看到存储的对象内容)。
正是由于不直观,所以我们一般把对象序列化方式调整为 Jackson2JsonRedisSerializer。配置类如下:
typescript
代码解读
复制代码
/** * redis配置序列化 * * @author 老马 * @date 2023-06-09 14:58 */ @Configuration public class RedisConfig { @Resource private RedisConnectionFactory factory; @Bean public RedisTemplate<String, Object> redisTemplate() { RedisSerializer<Object> serializer = redisSerializer(); RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public RedisSerializer<Object> redisSerializer() { // 创建JSON序列化器 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 必须设置,否则无法将json转化为对象,会转化为Map类型 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(objectMapper); return serializer; } }
再次通过测试方法设置redis的值,采用redis客户端工具观察:
1.5 加入连接池
有的时候我们想要给我们的redis客户端配置上连接池。就像我们连接mysql的时候,也会配置连接池一样,目的就是增加对于数据连接的管理,提升访问的效率,也保证了对资源的合理利用。
-
修改配置文件
yaml
代码解读
复制代码
spring: redis: host: 192.168.0.1 port: 6379 password: t+UUVnXZ6cysf3lr/N02d>ly+mwm/1P database: 0 connect-timeout: 10s lettuce: pool: #连接池中的最小空闲连接 min-idle: 8 #连接池中的最大空闲连接 max-idle: 16 #连接池最大连接数(负值表示无限制) max-active: 100
-
加入连接池的依赖
xml
代码解读
复制代码
<!-- 连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
导入连接池包前后RedisTemplate对象的对比:
2.集成jedis操作redis
2.1 依赖修改
xml
代码解读
复制代码
<!-- reids --> <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> <!-- jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
这里把SpringBoot默认的lettuce排除掉,下面引入jedis。
2.2 配置修改
yaml
代码解读
复制代码
spring: redis: host: 192.168.0.1 port: 6379 password: t+UUVnXZ6cysf3lr/N02d>ly+mwm/1P database: 0 connect-timeout: 10s # 这里仅仅把lettuce替换为jedis即可 # lettuce: jedis: pool: #连接池中的最小空闲连接 min-idle: 8 #连接池中的最大空闲连接 max-idle: 16 #连接池最大连接数(负值表示无限制) max-active: 100
2.3 进行测试
3.lettuce和jedis丝滑切换的原理
SpringBoot框架能通过各种starter进行无缝集成一个主要原因是其自动化配置功能。所谓自动化配置就是springBoot本身已经预先设置好了一些常用框架的整合类。然后通过类似于ConditionOn这样的条件判断注解,去辨别你的项目中是否有相关的类(或配置)了,进而进行相关配置的初始化。springBoot预设的自动化配置类都位于spring-boot-autoconfigure这个包中,只要我们搭建了springBoot的项目,这个包就会被引入进来。
这里可以看到这个RedisAutoConfiguration的配置类,打开看下:
再次打开引入的配置类看下:
-
lettuce
-
Jedis
至此就明白为什么我们把lettuce去掉引入jedis的依赖后,马上就采用jedis进行redis操作了。
4.redis工具类
typescript
代码解读
复制代码
package com.mayuanfei.springboot08.util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Redis工具类 * @author 老马 * @date 2023-06-09 17:17 */ @Component public class RedisUtil { @Autowired private RedisTemplate redisTemplate; /** * 给一个指定的 key 值附加过期时间 * * @param key * @param time * @return */ public boolean expire(String key, long time) { return redisTemplate.expire(key, time, TimeUnit.SECONDS); } /** * 根据key 获取过期时间 * * @param key * @return */ public long getTime(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 根据key 获取过期时间 * * @param key * @return */ public boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 移除指定key 的过期时间 * * @param key * @return */ public boolean persist(String key) { return redisTemplate.boundValueOps(key).persist(); } //- - - - - - - - - - - - - - - - - - - - - String类型 - - - - - - - - - - - - - - - - - /** * 根据key获取值 * * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 将值放入缓存 * * @param key 键 * @param value 值 * @return true成功 false 失败 */ public void set(String key, String value) { redisTemplate.opsForValue().set(key, value); } /** * 将值放入缓存并设置时间 * * @param key 键 * @param value 值 * @param time 时间(秒) -1为无期限 * @return true成功 false 失败 */ public void set(String key, String value, long time) { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { redisTemplate.opsForValue().set(key, value); } } /** * 批量添加 key (重复的键会覆盖) * * @param keyAndValue */ public void batchSet(Map<String, String> keyAndValue) { redisTemplate.opsForValue().multiSet(keyAndValue); } /** * 批量添加 key-value 只有在键不存在时,才添加 * map 中只要有一个key存在,则全部不添加 * * @param keyAndValue */ public void batchSetIfAbsent(Map<String, String> keyAndValue) { redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue); } /** * 对一个 key-value 的值进行加减操作, * 如果该 key 不存在 将创建一个key 并赋值该 number * 如果 key 存在,但 value 不是长整型 ,将报错 * * @param key * @param number */ public Long increment(String key, long number) { return redisTemplate.opsForValue().increment(key, number); } /** * 对一个 key-value 的值进行加减操作, * 如果该 key 不存在 将创建一个key 并赋值该 number * 如果 key 存在,但 value 不是 纯数字 ,将报错 * * @param key * @param number */ public Double increment(String key, double number) { return redisTemplate.opsForValue().increment(key, number); } //- - - - - - - - - - - - - - - - - - - - - set类型 - - - - - - - - - - - - - - - - - - /** * 将数据放入set缓存 * * @param key 键 * @return */ public void sSet(String key, String value) { redisTemplate.opsForSet().add(key, value); } /** * 获取变量中的值 * * @param key 键 * @return */ public Set<Object> members(String key) { return redisTemplate.opsForSet().members(key); } /** * 随机获取变量中指定个数的元素 * * @param key 键 * @param count 值 * @return */ public void randomMembers(String key, long count) { redisTemplate.opsForSet().randomMembers(key, count); } /** * 随机获取变量中的元素 * * @param key 键 * @return */ public Object randomMember(String key) { return redisTemplate.opsForSet().randomMember(key); } /** * 弹出变量中的元素 * * @param key 键 * @return */ public Object pop(String key) { return redisTemplate.opsForSet().pop("setValue"); } /** * 获取变量中值的长度 * * @param key 键 * @return */ public long size(String key) { return redisTemplate.opsForSet().size(key); } /** * 根据value从一个set中查询,是否存在 * * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { return redisTemplate.opsForSet().isMember(key, value); } /** * 检查给定的元素是否在变量中。 * * @param key 键 * @param obj 元素对象 * @return */ public boolean isMember(String key, Object obj) { return redisTemplate.opsForSet().isMember(key, obj); } /** * 转移变量的元素值到目的变量。 * * @param key 键 * @param value 元素对象 * @param destKey 元素对象 * @return */ public boolean move(String key, String value, String destKey) { return redisTemplate.opsForSet().move(key, value, destKey); } /** * 批量移除set缓存中元素 * * @param key 键 * @param values 值 * @return */ public void remove(String key, Object... values) { redisTemplate.opsForSet().remove(key, values); } /** * 通过给定的key求2个set变量的差值 * * @param key 键 * @param destKey 键 * @return */ public Set<Set> difference(String key, String destKey) { return redisTemplate.opsForSet().difference(key, destKey); } //- - - - - - - - - - - - - - - - - - - - - hash类型 - - - - - - - - - - - - - - - - - - /** * 加入缓存 * * @param key 键 * @param map 键 * @return */ public void add(String key, Map<String, String> map) { redisTemplate.opsForHash().putAll(key, map); } /** * 获取 key 下的 所有 hashkey 和 value * * @param key 键 * @return */ public Map<Object, Object> getHashEntries(String key) { return redisTemplate.opsForHash().entries(key); } /** * 验证指定 key 下 有没有指定的 hashkey * * @param key * @param hashKey * @return */ public boolean hashKey(String key, String hashKey) { return redisTemplate.opsForHash().hasKey(key, hashKey); } /** * 获取指定key的值string * * @param key 键 * @param key2 键 * @return */ public String getMapString(String key, String key2) { return redisTemplate.opsForHash().get("map1", "key1").toString(); } /** * 获取指定的值Int * * @param key 键 * @param key2 键 * @return */ public Integer getMapInt(String key, String key2) { return (Integer) redisTemplate.opsForHash().get("map1", "key1"); } /** * 弹出元素并删除 * * @param key 键 * @return */ public String popValue(String key) { return redisTemplate.opsForSet().pop(key).toString(); } /** * 删除指定 hash 的 HashKey * * @param key * @param hashKeys * @return 删除成功的 数量 */ public Long delete(String key, String... hashKeys) { return redisTemplate.opsForHash().delete(key, hashKeys); } /** * 给指定 hash 的 hashkey 做增减操作 * * @param key * @param hashKey * @param number * @return */ public Long increment(String key, String hashKey, long number) { return redisTemplate.opsForHash().increment(key, hashKey, number); } /** * 给指定 hash 的 hashkey 做增减操作 * * @param key * @param hashKey * @param number * @return */ public Double increment(String key, String hashKey, Double number) { return redisTemplate.opsForHash().increment(key, hashKey, number); } /** * 获取 key 下的 所有 hashkey 字段 * * @param key * @return */ public Set<Object> hashKeys(String key) { return redisTemplate.opsForHash().keys(key); } /** * 获取指定 hash 下面的 键值对 数量 * * @param key * @return */ public Long hashSize(String key) { return redisTemplate.opsForHash().size(key); } //- - - - - - - - - - - - - - - - - - - - - list类型 - - - - - - - - - - - - - - - - - - /** * 在变量左边添加元素值 * * @param key * @param value * @return */ public void leftPush(String key, Object value) { redisTemplate.opsForList().leftPush(key, value); } /** * 获取集合指定位置的值。 * * @param key * @param index * @return */ public Object index(String key, long index) { return redisTemplate.opsForList().index("list", 1); } /** * 获取指定区间的值。 * * @param key * @param start * @param end * @return */ public List<Object> range(String key, long start, long end) { return redisTemplate.opsForList().range(key, start, end); } /** * 把最后一个参数值放到指定集合的第一个出现中间参数的前面, * 如果中间参数值存在的话。 * * @param key * @param pivot * @param value * @return */ public void leftPush(String key, String pivot, String value) { redisTemplate.opsForList().leftPush(key, pivot, value); } /** * 向左边批量添加参数元素。 * * @param key * @param values * @return */ public void leftPushAll(String key, String... values) { redisTemplate.opsForList().leftPushAll(key, values); } /** * 向集合最右边添加元素。 * * @param key * @param value * @return */ public void leftPushAll(String key, String value) { redisTemplate.opsForList().rightPush(key, value); } /** * 向左边批量添加参数元素。 * * @param key * @param values * @return */ public void rightPushAll(String key, String... values) { redisTemplate.opsForList().rightPushAll(key, values); } /** * 向已存在的集合中添加元素。 * * @param key * @param value * @return */ public void rightPushIfPresent(String key, Object value) { redisTemplate.opsForList().rightPushIfPresent(key, value); } /** * 向已存在的集合中添加元素。 * * @param key * @return */ public long listLength(String key) { return redisTemplate.opsForList().size(key); } /** * 移除集合中的左边第一个元素。 * * @param key * @return */ public void leftPop(String key) { redisTemplate.opsForList().leftPop(key); } /** * 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。 * * @param key * @return */ public void leftPop(String key, long timeout, TimeUnit unit) { redisTemplate.opsForList().leftPop(key, timeout, unit); } /** * 移除集合中右边的元素。 * * @param key * @return */ public void rightPop(String key) { redisTemplate.opsForList().rightPop(key); } /** * 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。 * * @param key * @return */ public void rightPop(String key, long timeout, TimeUnit unit) { redisTemplate.opsForList().rightPop(key, timeout, unit); } }
5.代码地址
gitee.com/mayuanfei/S…下的springboot08
redission方式操作redis
1.简介
redisson是Redis官方推荐的一个客户端工具。它提供了使用Redis的最简单和最便捷的方法。除此之外,redisson还提供了可靠的分布式锁、布隆过滤器等功能。
文档地址: redisson中文文档
2.SpringBoot三板斧之添加依赖
官方比较推荐的starter包配置方式,这种方式会深度和Spring Data Redis模块结合。所以官方要求redisson-spring-data要和springboot的版本配合使用。否则有可能会引起莫名的问题。对应关系如下:
redisson-spring-data module name | Spring Boot version |
---|---|
redisson-spring-data-16 | 1.3.y |
redisson-spring-data-17 | 1.4.y |
redisson-spring-data-18 | 1.5.y |
redisson-spring-data-2x | 2.x.y |
redisson-spring-data-3x | 3.x.y |
这也就是说,redisson的starter可以比较新,但是redisson-spring-data要和springboot的版本对应。示例中的springboot的版本为2.7.10版本,pom引入:
xml
代码解读
复制代码
<!-- redisson--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.21.3</version> <exclusions> <exclusion> <artifactId>redisson-spring-data-30</artifactId> <groupId>org.redisson</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-data-27</artifactId> <version>3.21.3</version> </dependency>
3.SpringBoot三板斧之添加配置
yaml
代码解读
复制代码
spring: redis: # 地址 host: 192.168.0.1 # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码(如没有密码请注释掉) password: t+UUVnXZ6cys23dsd2d>ly+mwm/1P # 连接超时时间 timeout: 10s # 是否开启ssl ssl: false # redisson配置 redisson: # redis key前缀 keyPrefix: springboot09 # 线程池数量 threads: 4 # Netty线程池数量 nettyThreads: 8 # 单节点配置 singleServerConfig: # 客户端名称 clientName: laoma_macos # 最小空闲连接数 connectionMinimumIdleSize: 8 # 连接池大小 connectionPoolSize: 32 # 连接空闲超时,单位:毫秒 idleConnectionTimeout: 10000 # 命令等待超时,单位:毫秒 timeout: 3000 # 发布和订阅连接池大小 subscriptionConnectionPoolSize: 50
4.redisson配置类
redisson不但能操作redis,还依照Spring Cache标准提供了基于Redis的Spring缓存实现,每个缓存(Cache)实例都提供了了两个重要的可配置参数:过期时间(ttl)和最长空闲时间(maxIdleTime),如果这两个参数都未指定或值为0,那么实例管理的数据将永久保存。相对而已还比较复杂,配置类代码如下:
less
代码解读
复制代码
@Slf4j @Configuration @EnableCaching @EnableConfigurationProperties(RedissonProperties.class) public class RedisConfig { @Resource private RedissonProperties redissonProperties; @Resource private ObjectMapper objectMapper; @Bean public RedissonAutoConfigurationCustomizer redissonCustomizer() { return config -> { config.setThreads(redissonProperties.getThreads()) .setNettyThreads(redissonProperties.getNettyThreads()) .setCodec(new JsonJacksonCodec(objectMapper)); RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); if (ObjectUtil.isNotNull(singleServerConfig)) { // 使用单机模式 config.useSingleServer() .setTimeout(singleServerConfig.getTimeout()) .setClientName(singleServerConfig.getClientName()) .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); } // 集群配置方式 RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); if (ObjectUtil.isNotNull(clusterServersConfig)) { config.useClusterServers() .setTimeout(clusterServersConfig.getTimeout()) .setClientName(clusterServersConfig.getClientName()) .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) .setReadMode(clusterServersConfig.getReadMode()) .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); } log.info("初始化 redis 配置"); }; } /** * reission实现的缓存管理器 整合spring-cache */ @Bean public CacheManager cacheManager() { return new RedissonSpringCacheManager(SpringUtil.getBean(RedissonClient.class)); } }
这里配置的cacheManager采用的默认的redisson类。这种方式少了过期时间、最大空闲时间和组最大长度的配置,如果想更完善的使用spring cache,可以参考:blog.youkuaiyun.com/weixin_4046…这里进行配置。
5.测试类
Spring-cache注释的使用参考:blog.youkuaiyun.com/m0_67698950…
kotlin
代码解读
复制代码
/** * 表示这个方法有了缓存的功能,方法的返回值会被缓存下来 * 下一次调用该方法前,会去检查是否缓存中已经有值 * 如果有就直接返回,不调用方法 * 如果没有,就调用方法,然后把结果缓存起来 * 这个注解「一般用在查询方法上」 */ @Cacheable(cacheNames = "test:demo", key = "#userid", condition = "#userid != null") @GetMapping("/test3") public SysUser testRedis3(Long userid) { SysUser user = new SysUser(userid, "测试用户" + userid, "昵称" + userid); return user; } /** * 会把方法的返回值put到缓存里面缓存起来,供其它地方使用 * 它「通常用在新增或者实时更新方法上」 */ @CachePut(cacheNames = "test:demo", key = "#userid", condition = "#userid != null") @GetMapping("/test4") public SysUser testRedis4(Long userid) { SysUser user = new SysUser(userid, "测试用户" + userid, "昵称" + userid); return user; } /** * 使用了CacheEvict注解的方法,会清空指定缓存 * 「一般用在删除的方法上」 */ @CacheEvict(cacheNames = "test:demo", key = "#userid", condition = "#userid != null") @GetMapping("/test5") public String testRedis5(Long userid) { return "删除成功"; }
6.代码地址
gitee.com/mayuanfei/S…下的springboot09
redisson极简模式集成及其分布式锁使用
1.极简模式集成redisson
1.1加入依赖
xml
代码解读
复制代码
<!-- redisson--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.21.3</version> </dependency>
1.2添加配置
yaml
代码解读
复制代码
# redis基础配置 spring: redis: # 地址 host: 192.168.0.1 # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码(如没有密码请注释掉) password: t+UUVnXZ6cys23dsd2d>ly+mwm/1P # 连接超时时间 timeout: 10s # 是否开启ssl ssl: false
如果想对redisson有更多的配置,可以加入redssion的配置文件
yaml
代码解读
复制代码
spring: redis: redisson: file: classpath:redisson.yaml
配置文件可以参考: redisson中文文档
1.3测试通过redisson操作redis
typescript
代码解读
复制代码
@Resource private RedissonClient redissonClient; // 通过redisson操作redis @GetMapping("/test1") public String testRedis1() { JsonJacksonCodec jacksonCodec = new JsonJacksonCodec(); Map<String, Integer> map = new HashMap<>(); map.put("laoma", 44); map.put("cuidk", 43); RMap<Object, Object> lala = this.redissonClient.getMap("lala", jacksonCodec); lala.putAll(map); RBucket<Object> bucket = this.redissonClient.getBucket("aa:bb:cc", jacksonCodec); bucket.set(124); return JSONUtil.toJsonStr(lala); }
2.redisson实现分布式锁
分布式锁的应用场景:我们在用nginx把同一个程序进行集群部署时,由于每一个springboot程序都是单独的JVM,所以传统的synchronized和ReentrantLock已经都不好使了。这时,就考虑用redisson的分布式锁。
2.1锁原理
2.2示例代码
csharp
代码解读
复制代码
@Resource private RedissonClient redissonClient; public void updateUser(String userId) { String lockKey = "user" + userId; RLock lock = redissonClient.getLock(lockKey); //获取锁资源 try { lock.lock(10, TimeUnit.SECONDS); //加锁,可以指定锁定时间 //这里写需要处理业务的业务代码 } finally { lock.unlock(); //释放锁 } }
2.3代码地址
gitee.com/mayuanfei/S…下的springboot10
记忆印记
- springboot默认继承lettuce来操作redis的
- 可以利用redisson来操作redis,而且redisson封装了很多好用的方法。以后操作redis优先使用redisson
- redisson可以把java现有的类型,缓存到redis中,也就是可以在集群系统中,像访问同一个数据库一样
- 在集群或者分布式系统中,我们经常用redisson来实现分布式锁。