1. 程式人生 > >Redis之坑:Redis與MySQL中事務的區別

Redis之坑:Redis與MySQL中事務的區別

Note:

  1. 該篇討論的只是Redis與MySQL中事務的區別,並不能統一代表NO-SQL與關係型SQL;
  2. 在 MySQL 中只有使用了 Innodb 資料庫引擎的資料庫或表才支援事務;
  3. 事務使用的目的 是統一管理 insert,update,delete, 這些write操作,以此來維護資料完整性,並確定隔離級別,保證Select讀操作,下文討論的所有sql語句都是write操作

事務命令

MySQL:

  • BEGIN:顯式地開啟一個事務;
  • COMMIT:提交事務,將對資料庫進行的所有修改變成為永久性的;
  • ROLLBACK:結束使用者的事務,並撤銷正在進行的所有未提交的修改;

Redis:

  • MULTI:標記事務的開始;
  • EXEC:執行事務的commands佇列;
  • DISCARD:結束事務,並清除commands佇列;

Redis之坑:理解Redis事務 中我們通過類比MySQL的BEGAIN,COMMIT,ROLLBACK來理解Redis的事務命令。但是顯然,它們有著本質區別。

預設狀態

MySQL:

  • MySQL會預設開啟一個事務,且預設設定是自動提交,即,每成功執行一個SQL,一個事務就會馬上 COMMIT。所以不能Rollback。

Redis:

使用方式

**MySQL:**包含兩種

  1. 用 BEGIN, ROLLBACK, COMMIT,顯式開啟並控制一個 新的 Transaction。
  2. 執行命令SET AUTOCOMMIT=0,用來禁止當前會話自動commit,控制預設開啟的事務

Redis:

  1. 用 MULTI, EXEC, DISCARD,顯式開啟並控制一個Transaction(注意:這裡沒有強調**“新的”**,因為預設是不會開啟事務的)。

實現原理

很容易理解,Redis與MySQL中事務的區別其根本原因就是實現不同方式造成的。

MySQL:

  • MySQL實現事務,是基於UNDO/REDO日誌
  • UNDO日誌
    記錄修改前狀態,ROLLBACK基於UNDO日誌實現;
  • REDO日誌記錄修改後的狀態 ,COMMIT基於REDO日誌實現;
  • 在MySQL中無論是否開啟事務,SQL都會被立即執行並返回執行結果。只是**事務開啟**後執行後的狀態只是記錄在REDO日誌,執行COMMIT之後,資料才會被寫入磁碟
int insertSelective = serviceOrderMapper.insertSelective(s);

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

insertSelective = 受影響的行數;

Redis:

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

上述程式碼,

  • 如果沒有開啟事務,操作被立即執行,a 將會被立即賦值(true|false);
  • 如果開啟事務,操作未被立即之行,將會返回NULL值,而a的型別是boolean,所以將會丟擲異常:
    java.lang.NullPointerException