Redis事务及其Java实现

1.事务

1.1 事务概念

Redis中的事务是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。

这里写图片描述

127.0.0.1:6379> MULTI    //告诉Redis 后面会有多条命令同属一个事物,将命令加入队列
OK
127.0.0.1:6379> SET A 1
QUEUED  //说明  SET A 1 进入事物队列了
127.0.0.1:6379> SET B 2
QUEUED  //说明  SET B 1 进入事物队列了
127.0.0.1:6379> EXEC    //高如Redis顺序依次执行方才缓存的命令
1) OK   //执行命令的返回值
2) OK   //执行命令的返回值
127.0.0.1:6379> GET A
"1"
127.0.0.1:6379> GET B
"2"

Redis保证了事物中的所有命令要么都执行,要么都不执行。如果在执行EXEC命令之前客户端断线了,则Redis会清空事务队列, 事务中的所有命令都不会执行。

此外,Redis事务保证命令一次执行, 先进入事务队列的命令先执行, 后进入食物队列的命令后执行。

1.2 两类错误

在事务中,多条语句中的一条如果有错误,那么会怎么样呢?

来我们一起来做个试验

  • 语法错误

这里写图片描述

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET C 3
QUEUED
127.0.0.1:6379> SET
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> GET
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> 

可以看到,如果中间有错误,Redis会直接返回错误, 不执行任何操作 discarded

  • 运行错误
    运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行之前Redis是无法发现的,所以在事务里这样的命令是会被Redis接受并执行的。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令)

SADD key member [member …]
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
当 key 不是集合类型时,返回一个错误。


这里写图片描述

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET KEY 1
QUEUED
127.0.0.1:6379> SADD KEY 2
QUEUED
127.0.0.1:6379> SET KEY 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> 

Redis 的事务没有关系数据库事务提供的回滚(rollback)功能。为此开发者必须在事务执行出错后自己收拾剩下的摊子(将数据库复原会事务执行前的状态)

2.WATCH命令

有时需要根据前一条命令执行的返回值,来决定下一条命令是否执行,这时候就用法哦WATCH命令。它可以监控一个或多个键, 一旦其中一个键被修改或者删除,之后的事务就不会执行。

由于WATCH命令的作用只是当被监控的键值被修改后组织之后一个事务的执行,而不能保证其他客户端不修改这一键值, 所以我们需要在EXEC执行失败后重新执行整个事务函数。

这里写图片描述

127.0.0.1:6379> SET KEY 1
OK
127.0.0.1:6379> WATCH KEY
OK
127.0.0.1:6379> SET KEY 2
OK
127.0.0.1:6379> GET KEY
"2"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET KEY 3
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET KEY
"2"
127.0.0.1:6379>

3.Java实现

    @Test  
    public void testTansaction() {  
        Jedis jedis = new Jedis("127.0.0.1");  
        Transaction transaction = jedis.multi();  
        transaction.lpush("key", "11");  
        transaction.lpush("key", "22");    
        List<Object> list = transaction.exec(); 

        System.out.println(jedis.lrange("key",0,10));  
    }  

//打印输出结果如下
[22, 11]

下面来一个运行中报错:

    @Test  
    public void testTansaction2() {  
        Jedis jedis = new Jedis("127.0.0.1");  
        try {  
            Transaction transaction = jedis.multi();  
            transaction.lpush("QQ", "55");  
            int make_error = 1 / 0; 
            transaction.lpush("QQ", "66");  
            List<Object> list = transaction.exec();  
        } catch (Exception e) {  
            e.printStackTrace();
        }  
    }  
java.lang.ArithmeticException: / by zero
    at com.springmvc.redis.JedisTest.testTansaction2(JedisTest.java:54)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
......
..
..

通过数据库查看之后,发现整个事务并没有执行,因为中间出现异常退出了。

猜你喜欢

转载自blog.csdn.net/liberty12345678/article/details/82414084
今日推荐