跳到主要内容

Redis 事务

DeepSeek V3 中英对照 Redis Transactions

Redis 通过 multiexecdiscard 命令提供了对事务的支持。这些操作在 RedisTemplate 中是可用的。然而,RedisTemplate 并不能保证事务中的所有操作都在同一个连接中执行。

Spring Data Redis 提供了 SessionCallback 接口,用于在需要执行多个操作且使用相同 connection 的场景,例如在使用 Redis 事务时。以下示例展示了如何使用 multi 方法:

//execute a transaction
List<Object> txResults = redisOperations.execute(new SessionCallback<List<Object>>() {
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForSet().add("key", "value1");

// This will contain the results of all operations in the transaction
return operations.exec();
}
});
System.out.println("Number of items added to set: " + txResults.get(0));
java

RedisTemplate 使用其值、哈希键和哈希值序列化器在返回之前反序列化所有 exec 的结果。还有一个额外的 exec 方法,允许你为事务结果传递自定义的序列化器。

值得一提的是,如果在 multi()exec() 之间发生异常(例如,Redis 在超时时间内未响应导致超时异常),则连接可能会卡在事务状态中。为了防止这种情况,需要丢弃事务状态以清除连接:

List<Object> txResults = redisOperations.execute(new SessionCallback<List<Object>>() {
public List<Object> execute(RedisOperations operations) throws DataAccessException {
boolean transactionStateIsActive = true;
try {
operations.multi();
operations.opsForSet().add("key", "value1");

// This will contain the results of all operations in the transaction
return operations.exec();
} catch (RuntimeException e) {
operations.discard();
throw e;
}
}
});
java

@Transactional 支持

默认情况下,RedisTemplate 不会参与 Spring 管理的事务。如果你希望 RedisTemplate 在使用 @TransactionalTransactionTemplate 时能够利用 Redis 事务,你需要通过设置 setEnableTransactionSupport(true) 显式地为每个 RedisTemplate 启用事务支持。启用事务支持会将 RedisConnection 绑定到当前由 ThreadLocal 支持的事务中。如果事务在没有错误的情况下完成,Redis 事务将通过 EXEC 提交,否则将通过 DISCARD 回滚。Redis 事务是面向批处理的。在事务进行期间发出的命令会被排队,只有在提交事务时才会应用这些命令。

Spring Data Redis 在正在进行的事务中区分了只读命令和写命令。只读命令,例如 KEYS,会被传递到一个新的(非线程绑定的)RedisConnection 以允许读取操作。而写命令则由 RedisTemplate 进行排队,并在提交时应用。

以下示例展示了如何配置事务管理:

示例 1. 启用事务管理的配置

@Configuration
@EnableTransactionManagement 1
public class RedisTxContextConfiguration {

@Bean
public StringRedisTemplate redisTemplate() {
StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory());
// explicitly enable transaction support
template.setEnableTransactionSupport(true); 2
return template;
}

@Bean
public RedisConnectionFactory redisConnectionFactory() {
// jedis || Lettuce
}

@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
return new DataSourceTransactionManager(dataSource()); 3
}

@Bean
public DataSource dataSource() throws SQLException {
// ...
}
}
java
  • 配置 Spring 上下文以启用声明式事务管理

  • 配置 RedisTemplate 以通过将连接绑定到当前线程来参与事务。

  • 事务管理需要一个 PlatformTransactionManager。Spring Data Redis 不附带 PlatformTransactionManager 实现。假设你的应用程序使用 JDBC,Spring Data Redis 可以通过使用现有的事务管理器来参与事务。

以下示例各自展示了使用约束:

示例 2. 使用约束

// must be performed on thread-bound connection
template.opsForValue().set("thing1", "thing2");

// read operation must be run on a free (not transaction-aware) connection
template.keys("*");

// returns null as values set within a transaction are not visible
template.opsForValue().get("thing1");
java