Redis事务
本质:一组命令的集合 要么一起成功 要么一起失败,一个事务中的所有命令都会被序列化,在事务执行过程中会按照顺序执行
注意:
Redis单条命令是保证原子性的,但是事务是不保证原子性的
Redis没有隔离级别的概念
开启事务:multi
执行事务:exec
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 2
QUEUED
127.0.0.1:6379> set k2 3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 1
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "2"
4) OK
127.0.0.1:6379>
RedisTemplate中如何开启并执行事务?
public void testMultiFailure() {
// 开启事务支持,在同一个 Connection 中执行命令
stringRedisTemplate.setEnableTransactionSupport(true);
stringRedisTemplate.multi();
stringRedisTemplate.opsForValue().set(“name”, “qinyi”);
stringRedisTemplate.opsForValue().set(“gender”, “male”);
stringRedisTemplate.opsForValue().set(“age”, “19”);
stringRedisTemplate.exec()
System.out.println();
}
更常见的写法仍是采用 RedisTemplate 的默认配置,即不开启事务支持。
可以通过使用 SessionCallback,该接口保证其内部所有操作都是在同一个Session中。
@Test
@SuppressWarnings("all")
public void testSessionCallback() {
SessionCallback<Object> callback = new SessionCallback<Object>() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForValue().set("1", "11");
operations.opsForValue().set("2", "22");
operations.opsForValue().set("3", "33");
return operations.exec();
}
};
System.out.println(stringRedisTemplate.execute(callback));
}
execute
用于执行一个 Redis 命令,支持单个 Redis 命令以及事务操作。
官网解释:
黑马头条中的一个小案例
扫描主键,获取匹配partten的主键对应的值
/**
* 扫描主键,建议使用
* @param patten
* @return
*/
public Set<String> scan(String patten){
Set<String> keys = stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> result = new HashSet<>();
try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
.match(patten).count(10000).build())) {
while (cursor.hasNext()) {
result.add(new String(cursor.next()));
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
});
return keys;
}
这里用的是RedisCallback。
RedisCallback 和 SessionCallback 都是 Spring Data Redis 提供的两种回调接口,用于执行 Redis 操作。
参考链接: https://juejin.cn/post/7234103673344262199
- RedisCallback:表示一个针对 Redis 的操作回调,包括连接、命令执行和连接释放等过程。
- SessionCallback:用于 Redis 事务,表示一个针对 Redis 的事务操作回调,包括事务的开始、命令的执行和事务的提交或者回滚等过程。
前者执行单个命令,后者执行事务
executePipeline
用于执行多个 Redis 命令
将所有命令缓存在管道中,最终一次性发送给 Redis 服务器。这样可以减少与 Redis 服务器的通信次数,提高命令的执行效率和吞吐量。
官网案例
//pop a specified number of items from a queue
List<Object> results = stringRedisTemplate.executePipelined(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisConnection stringRedisConn = (StringRedisConnection)connection;
for(int i=0; i< batchSize; i++) {
stringRedisConn.rPop("myqueue");
}
return null;
}
});
黑马头条案例
/**
* 管道技术,提高性能
* @param type
* @param values
* @return
*/
public List<Object> refreshWithPipeline(String future_key,String topic_key,Collection<String> values){
List<Object> objects = stringRedisTemplate.executePipelined(new RedisCallback<Object>() {
@Nullable
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
StringRedisConnection stringRedisConnection = (StringRedisConnection)redisConnection;
String[] strings = values.toArray(new String[values.size()]);
stringRedisConnection.lPush(topic_key,strings);
stringRedisConnection.zRem(future_key,strings);
return null;
}
});
return objects;
}