Redis Transactions
Redis 通过 multi
、exec
和 discard
命令提供对 transactions 的支持。这些操作在 RedisTemplate
中可用。但是,RedisTemplate
不能保证使用相同的连接运行事务中的所有操作。
Redis provides support for transactions through the multi
, exec
, and discard
commands.
These operations are available on RedisTemplate
.
However, RedisTemplate
is not guaranteed to run all the operations in the transaction with the same connection.
Spring Data Redis 提供 SessionCallback
接口,可在需要使用相同的 connection
执行多个操作时使用,例如在使用 Redis 事务时。以下示例使用 multi
方法:
Spring Data Redis provides the SessionCallback
interface for use when multiple operations need to be performed with the same connection
, such as when using Redis transactions.The following example uses the multi
method:
//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
方法,允许你为事务结果传递自定义序列化器。
RedisTemplate
uses its value, hash key, and hash value serializers to deserialize all results of exec
before returning.
There is an additional exec
method that lets you pass a custom serializer for transaction results.
值得一提的是,如果在 multi()
和 exec()
之间发生异常(例如在 Redis 未在超时内做出响应时发生超时异常),则连接可能会陷入事务状态。为了防止这种情况,需要丢弃事务状态以清除连接:
It is worth mentioning that in case between multi()
and exec()
an exception happens (e.g. a timeout exception in case Redis does not respond within the timeout) then the connection may get stuck in a transactional state.
To prevent such a situation need have to discard the transactional state to clear the connection:
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
Support
默认情况下,RedisTemplate
不参与托管的 Spring 事务。如果你希望 RedisTemplate
在使用 @Transactional
或 TransactionTemplate
时使用 Redis 事务,则需要通过设置 setEnableTransactionSupport(true)
明确地启用每个 RedisTemplate
的事务支持。启用事务支持会将 RedisConnection
绑定到由 ThreadLocal
支持的当前事务。如果事务顺利完成,Redis 事务将使用 EXEC
提交,否则将使用 DISCARD
回滚。Redis 事务是面向批处理的。在进行事务期间发出的命令将被排队,仅在提交事务时应用。
By default, RedisTemplate
does not participate in managed Spring transactions.
If you want RedisTemplate
to make use of Redis transaction when using @Transactional
or TransactionTemplate
, you need to be explicitly enable transaction support for each RedisTemplate
by setting setEnableTransactionSupport(true)
.
Enabling transaction support binds RedisConnection
to the current transaction backed by a ThreadLocal
.
If the transaction finishes without errors, the Redis transaction gets commited with EXEC
, otherwise rolled back with DISCARD
.
Redis transactions are batch-oriented.
Commands issued during an ongoing transaction are queued and only applied when committing the transaction.
Spring Data Redis 区分正在进行的事务中的只读和写命令。只读命令(如 KEYS
)被传送到新的(非线程绑定的)RedisConnection
以允许读取。写命令由 RedisTemplate
排队并应用于提交。
Spring Data Redis distinguishes between read-only and write commands in an ongoing transaction.
Read-only commands, such as KEYS
, are piped to a fresh (non-thread-bound) RedisConnection
to allow reads.
Write commands are queued by RedisTemplate
and applied upon commit.
以下示例展示如何配置事务管理:
The following example shows how to configure transaction management:
@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 | Configures a Spring Context to enable {spring-framework-docs}/data-access.html#transaction-declarative[declarative transaction management]. |
2 | Configures RedisTemplate to participate in transactions by binding connections to the current thread. |
3 | Transaction management requires a PlatformTransactionManager .
Spring Data Redis does not ship with a PlatformTransactionManager implementation.
Assuming your application uses JDBC, Spring Data Redis can participate in transactions by using existing transaction managers. |
以下每个示例都演示了一个使用限制:
The following examples each demonstrate a usage constraint:
// 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");