詳細探究Redis事務與MySQL事務的區別【轉】


使用redis的小伙伴都知道,redis有事務的概念,同樣的,mysql中也有事務的概念,那么這兩者之間有什么關系呢?區別到底大不大?今天詳細總結了一下,我們來一探究竟~

在介紹區別之前,再次熟悉一下事務的概念:

 

0. 概念

事務:Transaction

本質是一組命令的集合,可以一次執行多個命令,所有命令都會序列化,按順序地串行化執行而不會被其它命令插入,不許插隊。將一組需要一起執行的命令放到multiexec兩個命令之間。multi命令代表事務開始,exec命令代表事務結束,它們之間的命令是原子順序執行的。

0.1 Redis事務的三個特性

  1. 單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷;

  2. 沒有隔離級別的概念:隊列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行,也就不存在”事務內的查詢要看到事務里的更新,在事務外查詢不能看到”這個讓人萬分頭痛的問題;

  3. 不保證原子性:redis同一個事務中如果有一條命令執行失敗,其后的命令仍然會被執行,沒有回滾;

0.2 Redis事務執行的三個階段

  1. 開啟:以MULTI開始一個事務;

  2. 入隊:將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務隊列里面;

  3. 執行:由EXEC命令觸發事務;

舉個例子:

1、正常執行:

 

 

 2、放棄事務

 

 3、全體連坐(命令集合中含有錯誤的指令(注意是語法錯誤),均連坐,全部失敗)

 

 4、冤有頭,債有主(運行時錯誤,即非語法錯誤正確命令都會執行,錯誤命令返回錯誤

 

 但是我們注意到,在錯誤指令后面的指令也會被執行,這里就是"get age"得到的是“11”。

好了,接下來我們看一下Mysql中的事務和redis中的事務的主要區別,

主要從以下四個方面:

1、事務命令

mysql:

  • Begin:顯式的開啟一個事務;
  • Commit:提交事務,將對數據庫進行的所有的修改變成永久性的;
  • Rollback:結束用戶的事務,並撤銷現在正在進行的未提交的修改;

redis:

  • Multi:標記事務的開始;
  • Exec:執行事務的commands隊列;
  • Discard:結束事務,並清除commands隊列;

2、默認狀態

mysql:

  • mysql會默認開啟一個事務,且缺省設置是自動提交,即每成功執行一次sql,一個事務就會馬上commit,所以不能rollback;
  • 默認情況下如上所述,但是非默認情況下,可以rollback

redis:

  • redis默認不會開啟事務,即command會立即執行,而不會排隊,並不支持rollback

3、使用方式

mysql(包含兩種方式):

  1. 用Begin、Rollback、commit顯式開啟並控制一個 新的 Transaction;
  2. 執行命令 set autocommit=0,用來禁止當前會話自動commit,控制 默認開啟的事務;

redis:

  1. 用multi、exec、discard,顯式開啟並控制一個Transaction。(注意:這里沒有強調 “新的” ,因為默認是不會開啟事務的)。

4、實現原理

mysql:

  • mysql實現事務,是基於undo/redo日志
  • undo記錄修改前狀態,rollback基於undo日志實現;
  • redo記錄修改后的狀態,commit基於redo日志實現;
  • 在mysql中無論是否開啟事務,sql都會被立即執行並返回執行結果,只是事務開啟執行后的狀態只是記錄在redo日志,執行commit之后,數據才會被寫入磁盤;

如: int insertSelective = serviceOrderMapper.insertSelective(s); 

上述代碼,insertSelective 將會被立即賦值(無論是否開啟事務,只是結果或未被寫入磁盤):

redis:

  • redis實現事務,是基於commands隊列;
  • 如果沒有開啟事務,command將會被立即執行並返回執行結果,並且直接寫入磁盤
  • 如果事務開啟,command不會被立即執行,而是排入隊列,並返回排隊狀態(具體依賴於客戶端(例如:spring-data-redis)自身實現)。調用exec才會執行commands隊列;
boolean a = redisTemplate.opsForZSet().add("generalService",orderId,System.currentTimeMillis());

上述代碼,

  • 如果沒有開啟事務,操作被立即執行,a將會被立即賦值(true/false);
  • 如果開啟事務,操作不會被立即執行,將會返回null值,而a的類型是boolean,所以將會拋出異常:java.lang.NullPointerException;

 

 

參考並致謝:

1.Redis & Mysql 讀寫一致性問題

2.Redis事務(Transaction)

 

 

Over......


免責聲明!

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



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