|
对于最新的稳定版本,请使用 Spring Data Redis 4.0.4! |
Redis 事务
Redis 通过 multi、exec 和 discard 命令提供对 事务 的支持。
这些操作可在 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));
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;
}
}
});
@Transactional支持
默认情况下,RedisTemplate 不参与受管理的 Spring 事务。
如果您希望在 @Transactional 或 TransactionTemplate 的使用过程中让 RedisTemplate 利用 Redis 事务,您需要通过设置 setEnableTransactionSupport(true) 为每个 RedisTemplate 显式启用事务支持。
启用事务支持会将 RedisConnection 绑定到当前事务,该事务由 ThreadLocal 提供支持。
如果事务顺利完成且无错误,Redis 事务将通过 EXEC 提交;否则将通过 DISCARD 回滚。
Redis 事务是面向批处理的。
在正在进行的事务中发出的命令会被排队,仅在提交事务时才应用。
Spring Data Redis 在正在进行的事务中区分只读命令和写命令。
只读命令(例如 KEYS)会被发送到一个全新的(非线程绑定的)RedisConnection,以允许执行读取操作。
写命令则由 RedisTemplate 进行排队,并在提交时执行。
以下示例展示了如何配置事务管理:
@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 {
// ...
}
}
| 1 | 配置一个 Spring 上下文以启用声明式事务管理。 |
| 2 | 配置 RedisTemplate 以通过将连接绑定到当前线程来参与事务。 |
| 3 | 事务管理需要一个 PlatformTransactionManager。
Spring Data Redis 本身并未提供 PlatformTransactionManager 的实现。
假设您的应用程序使用 JDBC,Spring Data Redis 可以通过使用现有的事务管理器参与事务。 |
以下每个示例都展示了一种使用限制:
// 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");