1.依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.9-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.事务使用报错
- 从jedis换到redisTemplate,使用事务会出现以下错误:
Caused by: io.lettuce.core.RedisCommandExecutionException: ERR DISCARD without MULTI
- 因为redisTemplate使用事务命令multi之后discard命令和exec命令二选一,因为不管执行哪一个代码最后都会关闭当前的连接,看源码:
public static void unbindConnection(RedisConnectionFactory factory) {
RedisConnectionHolder conHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);
if (conHolder == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("Unbinding Redis Connection");
}
if (conHolder.isTransactionActive()) {
if (log.isDebugEnabled()) {
log.debug("Redis Connection will be closed when outer transaction finished");
}
} else {
RedisConnection connection = conHolder.getConnection();
conHolder.released();
if (!conHolder.isOpen()) {
TransactionSynchronizationManager.unbindResourceIfPossible(factory);
doCloseConnection(connection); //关闭连接
}
}
}
3.事务回滚
redis配置:以下使用事务需要注意两点第一点是开启支持事务,以及事务的执行建议使用redisTemplate的execute方法实现接口,因为官网建议的spring官网https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#tx.spring
/**
* 序列化相关的配置
*/
@Bean("myRedisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//支持事务
redisTemplate.setEnableTransactionSupport(true);
//json方式序列化
Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer<>(Object.class);
redisTemplate.setConnectionFactory(factory);
//String方式序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//配置序列化的方式不用设置
/*redisTemplate.setDefaultSerializer();
redisTemplate.setStringSerializer();
redisTemplate.setEnableDefaultSerializer();*/
//设置所有的key为string方式序列化
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//设置所有的value为jackson方式序列化
redisTemplate.setValueSerializer(jackson);
redisTemplate.setHashValueSerializer(jackson);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
无效事务,在jedis,以下是可以回滚的
redisTemplate.execute(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
List<Object> exec = null;
try {
operations.multi();
operations.opsForValue().set((K) "username", (V) "wyx");
operations.opsForSet().members((K) "username"); //用set类型获取string类型的值,
exec = operations.exec();
} catch (Exception e) {
redisTemplate.discard();
}
return exec;
}
});
}
有效事务
redisTemplate.execute(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
List<Object> exec = null;
try {
operations.multi();
operations.opsForValue().set((K) "username", (V) "wyx");
operations.opsForSet().members((K) "username"); //用set类型获取string类型的值,
System.out.println(1/0); //redis命令使用的错误将不会回滚
exec = operations.exec();
} catch (Exception e) {
redisTemplate.discard();
}
return exec;
}
});
}