Redis之坑:Redis與MySQL中事務的區別
阿新 • • 發佈:2019-01-02
Note:
- 該篇討論的只是Redis與MySQL中事務的區別,並不能統一代表NO-SQL與關係型SQL;
- 在 MySQL 中只有使用了
Innodb
資料庫引擎的資料庫或表才支援事務;- 事務使用的目的 是統一管理 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:
- 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