redis事务的本质是:一组命令的集合,一个事务中所有命令都会被按顺序放在队列中,在发起执行命令的时候队列中的命令会被一一执行
- Redis事务没有隔离级别的概念
- Redis单条命令保证原子性,但是事务不保证原子性
redis事务:
- 开启事务(multi)
- 命令入队(……)
- 执行事务(exec)
正常执行事务
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) OK
4) "v3"
放弃事务的执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k2
(nil)
命令错误 所有的命令都不会被执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> sett k1 v2
(error) ERR unknown command `sett`, with args beginning with: `k1`, `v2`,
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
运行时异常,队列中的命令存在语法性的错误,执行的时候其他命令是可以执行的,错误命令抛出异常
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 "v1"
QUEUED
127.0.0.1:6379> incr k1 #有语法错误,其作用是为k1上的值加1,如果k1的值不是数字就会报错
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "v2"
监控命令
watch(乐观锁机制)
127.0.0.1:6379> watch money #监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10 #让money减10
QUEUED
127.0.0.1:6379> exec #在执行前开启另外一个客户端修改money的值,就会执行失败
(nil)
127.0.0.1:6379> get money
(nil)
127.0.0.1:6379> set money 100
OK
如果修改失败,我们将其解锁再重新监控就好
127.0.0.1:6379> Unwatch #解锁
OK
127.0.0.1:6379> watch money #重新监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10 #让money减10
QUEUED
127.0.0.1:6379> exec #执行
1) (integer) 90
代码中使用Redis
Jedis是Redis官方推荐的Java连接Redis工具
导入包:
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
Jedis所有函数都与Redis中的命令行相同
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
/**
* redis测试
* 测试redis的事务
*/
public class RedisDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.flushDB();
Transaction multi = jedis.multi();
try {
multi.set("user1", "张三");
multi.set("user2", "李四");
int i = 1/0;// 报错放弃事务
multi.exec();
} catch (Exception e){
multi.discard();// 放弃事务
e.printStackTrace();
}finally {
jedis.close();
}
System.out.println(jedis.get("user1"));
}
}
输出:
java.lang.ArithmeticException: / by zero
at RedisDemo.main(RedisDemo.java:17)
null