Jedis事務
咱們使用JDBC鏈接Mysql的時候,每次執行sql語句以前,都須要開啓事務;在MyBatis中,
也須要使用openSession()來獲取session事務對象,來進行sql執行、查詢等操做。當咱們
對數據庫的操做結束的時候,是事務對象負責關閉數據庫鏈接。
事務對象用於管理、執行各類數據庫操做的動做。它可以開啓和關閉數據庫鏈接,執行sql
語句,回滾錯誤的操做。
咱們的Redis也有事務管理對象,其位於redis.clients.jedis.Transaction下。
Jedis事務的相關代碼:java
- package cn.com.redis;
-
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.Transaction;
-
- public class Test7 {
- public static void main(String[] args) {
- Jedis jedis = new Jedis("192.168.248.129",6379);
-
- Transaction transaction=jedis.multi();
-
-
- transaction.set("k4", "v4");
- transaction.set("k5", "v5");
-
- transaction.exec();
- }
- }
咱們查看一下redis:
![](http://static.javashuo.com/static/loading.gif)
發現數據已經加入進去
咱們把k4的value和k5的value改成「v44」和「v55」,
而後在transaction.exec()語句後加入transaction.discard()語句:redis
- package cn.com.redis;
-
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.Transaction;
-
- public class Test7 {
- public static void main(String[] args) {
- Jedis jedis = new Jedis("192.168.248.129",6379);
-
- Transaction transaction=jedis.multi();
-
-
- transaction.set("k4", "v44");
- transaction.set("k5", "v55");
-
- transaction.discard();
- }
- }
會發現數據插入操做被回滾,redis中那兩個值未被改變:
![](http://static.javashuo.com/static/loading.gif)
咱們模擬一個刷一次信用卡的交易,使用redis的事務來處理一些邏輯:sql
- package cn.com.redis;
-
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.Transaction;
-
- public class TestTransaction {
-
- public static void main(String[] args) {
- TestTransaction t = new TestTransaction();
- boolean retValue = t.transMethod(100);
- if(retValue){
- System.out.println("使用信用卡消費成功!");
- }else{
- System.out.println("使用信用卡消費失敗!");
- }
-
- }
-
-
- private boolean transMethod(int amount) {
-
- System.out.println("您使用信用卡預付款"+amount+"元");
-
- Jedis jedis = new Jedis("192.168.248.129",6379);
-
- int balance = 1000;
- int debt;
- int amtToSubtract = amount;
-
- jedis.set("balance", String.valueOf(balance));
- jedis.watch("balance");
-
- balance = Integer.parseInt(jedis.get("balance"));
- if(balance < amtToSubtract){
- jedis.unwatch();
- System.out.println("可用餘額不足!");
- return false;
- }else{
- System.out.println("扣費transaction事務開始執行...");
- Transaction transaction = jedis.multi();
- transaction.decrBy("balance",amtToSubtract);
- transaction.incrBy("debt", amtToSubtract);
- transaction.exec();
- balance = Integer.parseInt(jedis.get("balance"));
- debt = Integer.parseInt(jedis.get("debt"));
- System.out.println("扣費transaction事務執行結束...");
-
- System.out.println("您的可用餘額:"+balance);
- System.out.println("您目前欠款:"+debt);
- return true;
- }
- }
-
- }
此代碼就是模擬用戶使用信用卡刷了100元的東西,此時應該減去信用卡的可用餘額100元,
增長100元的欠款。
運行結果:
![](http://static.javashuo.com/static/loading.gif)
redis的結果:
![](http://static.javashuo.com/static/loading.gif)
證實咱們的操做是成功的。
加watch命令是爲了在事務執行的過程當中,防止其它的操做打斷事務,或者是影響事務的計算結果,
致使「幻讀」、「髒數據」等異常狀況的發生。watch命令創建了一個鍵,一旦發現執行過程當中該
鍵被別人修改過,那事務就會失敗,程序中一般能夠捕獲這類錯誤再從新執行一次,直到成功。
因此watch命令能夠保證數據的同步安全。
爲了證實watch命令的用途,咱們把上面代碼裏面的jedis.set("balance", "1100");註釋釋放,
而後transMethod方法拋出打斷異常:throws InterruptedException,main方法捕獲打斷異常,
而後彈出相應警告框。數據庫
- package cn.com.redis;
-
- import java.util.List;
-
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.Transaction;
-
- public class TestTransaction {
-
- public static void main(String[] args) {
- TestTransaction t = new TestTransaction();
- boolean retValue=false;
- boolean Interrupted = false;
-
- try {
- retValue = t.transMethod(100);
- } catch (InterruptedException e) {
- Interrupted = true;
- System.out.println("事務被打斷,請從新執行!");
- }finally{
- if(retValue){
- System.out.println("使用信用卡消費成功!");
- }else{
- if(!Interrupted){
- System.out.println("使用信用卡消費失敗!餘額不足!");
- }
- }
- }
- }
-
-
- private boolean transMethod(int amount) throws InterruptedException{
-
- System.out.println("您使用信用卡預付款"+amount+"元");
-
- Jedis jedis = new Jedis("192.168.248.129",6379);
-
- int balance = 1000;
- int debt;
- int amtToSubtract = amount;
-
- jedis.set("balance", String.valueOf(balance));
- jedis.watch("balance");
- jedis.set("balance", "1100");
- balance = Integer.parseInt(jedis.get("balance"));
- if(balance < amtToSubtract){
- jedis.unwatch();
- System.out.println("可用餘額不足!");
- return false;
- }else{
- System.out.println("扣費transaction事務開始執行...");
- Transaction transaction = jedis.multi();
- transaction.decrBy("balance",amtToSubtract);
- transaction.incrBy("debt", amtToSubtract);
- List<Object> result = transaction.exec();
-
- if(result==null){
-
- System.out.println("扣費transaction事務執行中斷...");
- throw new InterruptedException();
-
- }else{
- balance = Integer.parseInt(jedis.get("balance"));
- debt = Integer.parseInt(jedis.get("debt"));
- System.out.println("扣費transaction事務執行結束...");
-
- System.out.println("您的可用餘額:"+balance);
- System.out.println("您目前欠款:"+debt);
-
- return true;
- }
- }
- }
-
- }
再運行一下,看一下效果:
![](http://static.javashuo.com/static/loading.gif)
這就說明了,若是在watch命令執行後和事務提交以前,若是數據發生了修改操做,事務執行就不會成功,安全