Redis之坑:Redis與MySQL中事務的區別
阿新 • • 發佈:2019-12-31
Note:
- 該篇討論的只是Redis與MySQL中事務的區別,並不能統一代表NO-SQL與關係型SQL;
- 在 MySQL 中只有使用了
Innodb
資料庫引擎的資料庫或表才支援事務;
事務命令
MySQL:
- BEGIN:顯式地開啟一個事務;
- COMMIT:提交事務,將對資料庫進行的所有修改變成為永久性的;
- ROLLBACK:結束使用者的事務,並撤銷正在進行的所有未提交的修改;
Redis:
- MULTI:標記事務的開始;
- EXEC:執行事務的commands佇列;
- DISCARD:結束事務,並清除commands佇列;
Redis之坑:理解Redis事務 中我們通過類比MySQL的BEGAIN
COMMIT
,ROLLBACK
來理解Redis的事務命令。但是顯然,它們有著本質區別。
預設狀態
MySQL:
- MySQL會預設開啟一個事務,且預設設定是自動提交,即,每成功執行一個SQL,一個事務就會馬上 COMMIT。所以不能Rollback。
Redis:
- Redis預設不會開啟事務,即command會立即執行,而不會排隊。並不支援Rollback(詳情可見:Redis之坑:理解Redis事務 )
使用方式
MySQL: 包含兩種
- 用 BEGIN,ROLLBACK,COMMIT,顯式開啟並控制一個 新的 Transaction。
- 執行命令SET AUTOCOMMIT=0,用來禁止當前會話自動commit,控制預設開啟的事務
Redis:
- 用 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