使用Java操作Redis事务

事务

Redis 事务可以一次执行多个命令,有两个特性:
  • 隔离性:事务的所有命令都会序列化、按顺序的执行,事务执行完后才会执行其他客服端的命令。

  • 原子性: 事务中的命令要么全部被执行,要么全部不执行。

使用你事务时会遇到两个错误:
  • 入队时出错,一般时因为语法错误引起的,加入事务队列就会报错,遇到这类错误,一般会放弃事务

  • EXEC调用后出错,列如对一个 值为 a1key 执行 incr,这类错误,即使某个命令产生了错误,其他命令依旧会继续执行执行,不会回滚

Reids 中的 WATCH命令

使用 WATCH 命令可以监控键,如果被监控的键,再 EXEC 之前被修改,那么事务会放弃执行(注意:事务中的命令在 exec命令后才开始执行)

EXEC 执行以后,无论事务是否执行成功,都会放弃对所有键的监控。

使用Java操控Redis事务命令
// 开启事务
Transaction transaction = jedis.multi();
// 提交事务
transaction.exec();
// 放弃事务
transaction.discard();
// 监控键
jedis.watch("balance", "debt");
// 放弃所有被监控的键
jedis.unwatch();

完整代码示例:

package com.project.test;

import java.util.List;

import org.junit.Before;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

/**
 * Rdis 事务
 *
 */
public class TestTX {
    
    static final Jedis jedis = new Jedis("132.232.6.208", 6381);
    /**
     * 清空数据库
     */
    @Before
    public void flushdb() {
        jedis.flushDB();
    }
    
    @Test
    public void commitTest() {
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        transaction.set("key-1", "value-1");
        transaction.set("key-2", "value-2");
        transaction.set("key-3", "value-3");
        transaction.set("key-4", "value-4");
        
        // 提交事务
        transaction.exec();
        
        System.out.println(jedis.keys("*"));
    }
    
    
    @Test
    public void discardTest() {
        
        // 开启事务
        Transaction transaction = jedis.multi();
        
        transaction.set("key-1", "value-1");
        transaction.set("key-2", "value-2");
        transaction.set("key-3", "value-3");
        transaction.set("key-4", "value-4");
        
        // 放弃事务
        transaction.discard();
        
        System.out.println(jedis.keys("*"));
    }
    
    /**
     * watch 命令会标记一个或多个键
     * 如果事务中被标记的键,在提交事务之前被修改了,那么事务就会失败。
     * @return 
     * @throws InterruptedException 
     */
    @Test
    public void watchTest() throws InterruptedException {
        boolean resultValue = transMethod(10);
        System.out.println("交易结果(事务执行结果):" + resultValue);
        
        int balance = Integer.parseInt(jedis.get("balance"));
        int debt = Integer.parseInt(jedis.get("debt"));
        
        System.out.printf("balance: %d, debt: %d
", balance, debt);
    }
    
    // 支付操作
    public static boolean transMethod(int amtToSubtract) throws InterruptedException {
        int balance;  // 余额
        int debt;  // 负债
        
        jedis.set("balance", "100");
        jedis.set("debt", "0");
        
        jedis.watch("balance", "debt");
        
        balance = Integer.parseInt(jedis.get("balance"));
        
        // 余额不足
        if (balance < amtToSubtract) {
            jedis.unwatch();  // 放弃所有被监控的键
            System.out.println("Insufficient balance");
            
            return false;
        }
        
        Transaction transaction = jedis.multi();
        // 扣钱
        transaction.decrBy("balance", amtToSubtract);
        Thread.sleep(5000);  // 在外部修改 balance 或者 debt
        transaction.incrBy("debt", amtToSubtract);
        
        // list为空说明事务执行失败
        List<Object> list = transaction.exec();
        
        return !list.isEmpty();
    }
}
原文地址:https://www.cnblogs.com/47Gamer/p/13727431.html