使用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\n", 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();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM