Maven 整合 Jedis
在 Maven 中引入 Jedis 就可以使用了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class DemoTest { private Jedis jedis;
@BeforeEach public void getReids() { jedis = new Jedis("server.xorex.space", 6379); jedis.auth("tempestxorex"); }
@Test public void test() { String result = jedis.set("tempest", "xorex"); System.out.println(result);
result = jedis.get("tempest"); System.out.println(result); }
@AfterEach public void closeRedis() { if (jedis != null) { jedis.close(); } } }
|
Redis 虽然是原子性线程安全的,但是 Jedis 在获取和修改 Redis 的时候的代码,是线程不安全的。也就是如果多个 Java 线程共享一个 jedis 链接实例,就会出现线程不安全问题。为了解决这个问题,可以建立多个 jedis 的连接池,为每个 Java 线程分配不同的 jedis 连接实例。
创建连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class JedisConnectionPoolFactory { private static final JedisPool jedisPool;
static { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(8); config.setMinIdle(8); config.setMaxWait(Duration.ZERO);
jedisPool = new JedisPool(config, "server.xorex.space", 6379, 1000, "tempestxorex"); }
public Jedis getJedis() { return jedisPool.getResource(); } }
|
使用连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class DemoTest { private Jedis jedis;
@BeforeEach public void getReids() { jedis = JedisConnectionPoolFactory.getJedis(); }
@AfterEach public void closeRedis() { if (jedis != null) { jedis.close(); } } }
|
SpringBoot 整合 Jedis
前置操作
这里是使用 Spring 全家桶中的 SpringData 系列(专注于数据处理)的 SpringDataRedis,它封装了第三方的 Redis Java 客户端,提供了统一的操作接口。
使用依赖:
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
|
引入完成之后,就是在 SpringBoot 的配置文件里面去配置 Redis 的信息。需要注意的是,SpringDataRedis 默认只下载了 lettuce 客户端,如果需要用 Jedis,那么就要引入 Jedis 的 Maven 了。版本号 SpringBoot 会仲裁。
1 2 3 4
| <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
|
完成配置:
1 2 3 4 5 6 7 8 9 10 11 12
| spring: redis: host: xxxxxxxx port: 6379 password: xxxxxxx database: 0 jedis: pool: max-active: 8 max-idle: 8 max-wait: 100ms min-idle: 0
|
SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作 API 封装到了不同的类型中:
API |
返回值类型 |
说明 |
redisTemplate.opsForValue() |
ValueOperations |
操作String类型数据 |
redisTemplate.opsForHash() |
HashOperations |
操作Hash类型数据 |
redisTemplate.opsForList() |
ListOperations |
操作List类型数据 |
redisTemplate.opsForSet() |
SetOperations |
操作Set类型数据 |
redisTemplate.opsForZSet() |
ZSetOperations |
操作SortedSet类型数据 |
redisTemplate |
|
通用的命令 |
操作 Redis:
1 2 3 4 5 6 7 8 9 10 11
| @SpringBootTest public class JedisTest { @Autowired private RedisTemplate redisTemplate;
@Test public void getJedis() { redisTemplate.opsForValue().set("testKey", "testValue"); } }
|
对象序列化存储问
RedisTemplate 的两种序列化实践方案:
方案一:
- 自定义 RedisTemplate
- 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer
方案二:
- 使用 StringRedisTemplate
- 写入 Redis 时,手动把对象序列化为 JSON
- 读取 Redis 时,手动把读取到的 JSON 反序列化为对象
方案一:
需要注意的是, RedisTemplate 操作的时候,输入的 Key 和 Value 都是 Object 对象,那么就需要有专门的工具类将对象转换为 Redis 需要的 Key 和 Value 字符串。
这个专门工具类的设置,是作用在 RedisTemplate 上面的,需要我们去修改他的参数。那么在 SpringBoot 中很好解决,只需要我们自定义一个 RedisTemplate,然后注入到 Spring 的 IOC 容器就可以了。这样我们 @AutoWired 拿到的就是我们自定义的 RedisTemplate 而不是默认创建的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(RedisSerializer.json()); redisTemplate.setHashValueSerializer(RedisSerializer.json());
return redisTemplate; } }
|
这样以后 @AutoWired 获取的 RedisTemplate 就是我们自己设置的了,中文编码也就不会出问题了。
- 自动完成对象和 Json 字符串的序列化和反序列化:
1 2 3 4 5 6 7 8
| public void test() { redisTemplate.opsForValue().set("user:100",new User(100,"Xorex",20));
User user = (User) redisTemplate.opsForValue().get("user:100"); System.out.println(user); }
|
1 2 3 4 5 6
| { "@class": "space.xorex.boot.pojo.User", "id": 101, "userName": "你好", "age": 20 }
|
方案二:
因为自动反序列化的结果多了一个 @Class,比较占用内存,我们可以通过将 Value 也设置为 String 序列化,这样就没有 @Class 了,但是这样做的坏处就是 get() 获取的 Redis 数据没有办法自动反序列化为对象了,需要我们手动完成。
Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认就是 String 方式。省去了我们自定义 RedisTemplate 的过程.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void test() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper();
User user = new User(101,"你好",20);
String json = mapper.writeValueAsString(user);
stringRedisTemplate.opsForValue().set("user:101",json);
String value = stringRedisTemplate.opsForValue().get("user:101");
User newUser = mapper.readValue(json, User.class); System.out.println(newUser); }
|
1 2 3 4 5
| { "id": 101, "userName": "你好", "age": 20 }
|