Redis Transactions Redis事务
Redis通过三个命令multi、exec、discard提供了对事务的支持。同样RedisTemplate 也支持这些操作,然而RedisTemplate 并不能保证使用同一个连接来执行事务中所有的操作。
当使用Redis 事务时,Spring Data Redis提供了SessionCallback 接口,来支持在同一个连接中执行多个操作。
代码示例如下:
//execute a transaction
List<Object> txResults = redisTemplate.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 ops in the transaction
return operations.exec();
}
});
System.out.println("Number of items added to set: " + txResults.get(0));
RedisTemplate将在返回所有exec的结果前,使用它的各种(值、哈希键、哈希值)序列化器对结果进行反序列化。还有一个额外的exec 方法,该方法能通过传递一个自定义的序列化器来转化结果。
在1.1版本中,RedisConnection 和RedisTemplate 对exec 方法做了一个重大的改变。以前该方法从连接器直接返回事务的结果。这意味着这些数据类型和RedisConnection方法返回的是不同的。例如,zAdd方法返回一个boolean类型来标识一个元素已经被添加到sorted set中了。大多数连接器返回一个long类型的值,而由Spring Data Redis来执行转换。另外一个普遍的不同点是,大多数的连接器在执行完操作(如:set)后会返回一个应答状态(通常是OK字符串)。这些应答会被Spring Data Redis丢弃。在1.1之前,exec 的结果不进行转化。而且,RedisTemplate也不会对结果进行反序列化,所以它们经常包含原生的字节数组。如果这些改变破坏了你的应用,你可以在你的RedisConnectionFactory 中设置convertPipelineAndTxResults 为false 来disable 掉这些行为。
1. @Transactional Support
支持@Transactional注解
默认情况下RedisTemplate 是不支持事务的,要使用事务需要明确的设置 setEnableTransactionSupport(true)。设置后会强制的绑定当前使用的RedisConnection到当前线程上,来触发MULTI。如果事务没有出错顺利完成了,EXEC会被调用,否则DISCARD将会被调用。一旦执行MULTI,RedisConnection会将所有操作写入队列,所有只读的操作像KEYS会被导向一个新的(non thread bound)RedisConnetion。
/** Sample Configuration **/
@Configuration
public class RedisTxContextConfiguration {
@Bean
public StringRedisTemplate redisTemplate() {
StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory());
// explicitly enable transaction support
template.setEnableTransactionSupport(true);
return template;
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public RedisConnectionFactory redisConnectionFactory( // jedis, lettuce, srp,... );
@Bean
public DataSource dataSource() throws SQLException { // ... }
}
/** Usage Constrainsts **/
// executed on thread bound connection
template.opsForValue().set("foo", "bar");
// read operation executed on a free (not tx-aware)
connection template.keys("*");
// returns null as values set within transaction are not visible
template.opsForValue().get("foo");