溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL和Redis事務(wù)的區(qū)別和用法

發(fā)布時(shí)間:2020-05-25 15:06:44 來源:PHP中文網(wǎng) 閱讀:224 作者:三月 欄目:MySQL數(shù)據(jù)庫

本篇文章給大家主要講的是關(guān)于MySQLRedis事務(wù)的區(qū)別和用法的內(nèi)容,感興趣的話就一起來看看這篇文章吧,相信看完MySQL和Redis事務(wù)的區(qū)別和用法對大家多少有點(diǎn)參考價(jià)值吧。                                                          

Redis

[1] Redis 事務(wù)可以一次執(zhí)行多個(gè)命令, 并且?guī)в幸韵聝蓚€(gè)重要的保證:

  • 批量操作在發(fā)送 EXEC 命令前被放入隊(duì)列緩存。
  • 收到 EXEC 命令后進(jìn)入事務(wù)執(zhí)行,事務(wù)中任意命令執(zhí)行失敗,其余的命令依然被執(zhí)行。
  • 在事務(wù)執(zhí)行過程,其他客戶端提交的命令請求不會插入到事務(wù)執(zhí)行命令序列中。

一個(gè)事務(wù)從開始到執(zhí)行會經(jīng)歷以下三個(gè)階段:

  • 開始事務(wù)。
  • 命令入隊(duì)。
  • 執(zhí)行事務(wù)。

單個(gè) Redis 命令的執(zhí)行是原子性的,但 Redis 沒有在事務(wù)上增加任何維持原子性的機(jī)制,所以 Redis 事務(wù)的執(zhí)行并不是原子性的。

事務(wù)可以理解為一個(gè)打包的批量執(zhí)行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會導(dǎo)致前面已做指令的回滾,也不會造成后續(xù)的指令不做。

操作錯(cuò)誤

看著有點(diǎn)兒繞口,那就實(shí)際執(zhí)行一下 看一下結(jié)果。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set tr_1 233
QUEUED
127.0.0.1:6379> lpush tr_1 666
QUEUED
127.0.0.1:6379> set tr_2 888
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK

在上面的事務(wù)中,設(shè)置了一個(gè) key 為 tr_1 的字符串?dāng)?shù)據(jù),然后又通過 lpush 來添加元素,這很明顯是錯(cuò)誤的操作方式,當(dāng)我們提交事務(wù)候出現(xiàn)了一個(gè)操作錯(cuò)誤,這時(shí)候我們來看看 tr_1 的值是什么。

127.0.0.1:6379> get tr_1
"233"

通過 get 命令來的tr_1 內(nèi)容還是 233 ,并沒有變,那再看一下其他的。

127.0.0.1:6379> keys *
1) "tr_2"
2) "tr_1"
127.0.0.1:6379> get tr_2
"888"
127.0.0.1:6379>

這里可以看到 tr_2 存在,并打印了值,這時(shí)候我們發(fā)現(xiàn),即使出現(xiàn)了操作錯(cuò)誤 ,但是錯(cuò)誤并沒有致使執(zhí)行停止,錯(cuò)誤之后的語句也執(zhí)行了并成功執(zhí)行,似乎符合上面提到的 中間某條指令的失敗不會導(dǎo)致前面已做指令的回滾,也不會造成后續(xù)的指令不做。

語法錯(cuò)誤

NO~,這時(shí)候還有另外一種情況 語法錯(cuò)誤

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set tr_1 233
QUEUED
127.0.0.1:6379> lpush tr_1 666
QUEUED
127.0.0.1:6379> set
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set 233
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set tr_2 888
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set)

當(dāng)我們執(zhí)行到 set時(shí)沒有給任何參數(shù),第二次執(zhí)行時(shí)故意少給了一個(gè)參數(shù)??梢钥吹綀?bào)了 語法錯(cuò)誤,最后提交事務(wù),也告訴了我們事務(wù)因?yàn)殄e(cuò)誤被丟失了,接著用 keys *檢索發(fā)現(xiàn)確實(shí)如此。

文檔釋義

這里可以官方文檔中提到的

Errors inside a transaction

// 在執(zhí)行過程中 可能會遇到兩種錯(cuò)誤命令錯(cuò)誤。

During a transaction it is possible to encounter two kind of command errors:

// 1.命令無法進(jìn)入隊(duì)列 ,比如 :參數(shù)數(shù)量錯(cuò)誤,命令名錯(cuò)誤...,或者某些關(guān)鍵錯(cuò)誤 如內(nèi)存不足

  • A command may fail to be queued, so there may be an error before EXEC is called. For instance the command may be syntactically wrong (wrong number of arguments, wrong command name, ...), or there may be some critical condition like an out of memory condition (if the server is configured to have a memory limit using the maxmemorydirective).

// 2. 對鍵進(jìn)行錯(cuò)誤的操作 如上面的 對字符串使用 lpush

  • A command may fail after EXEC is called, for instance since we performed an operation against a key with the wrong value (like calling a list operation against a string value).

// 客戶端檢查鍵入的命令,大多數(shù)時(shí)候會在調(diào)用 exec 前發(fā)現(xiàn)第一類錯(cuò)誤,如果命令執(zhí)行返回來 QUEUED 則表示命令正常進(jìn)入隊(duì)列,否則錯(cuò)誤,大多數(shù)情況下客戶端會終止放棄這個(gè)事務(wù)。

Clients used to sense the first kind of errors, happening before the EXEC call, by checking the return value of the queued command: if the command replies with QUEUED it was queued correctly, otherwise Redis returns an error. If there is an error while queueing a command, most clients will abort the transaction discarding it.

關(guān)于 Redis 暫時(shí)看到這里 接下來看到 MySQL

MySQL

眾所周知,MySQL 只有 InnoDB 引擎支持 事務(wù),在啟用 MySQL 事務(wù)之前需要先停掉自動(dòng)提交

測試表結(jié)構(gòu) user
類型注釋
idint(11) 自動(dòng)增量主鍵ID
moneyint(11) [0]金錢
titlevarchar(500) NULL稱呼

在這里來模擬一個(gè)轉(zhuǎn)賬的操作:A給B轉(zhuǎn)100元。

步驟解析 A+100 元,B -100元,即兩步雖然很簡單,簡單走一下流程。

MySQL和Redis事務(wù)的區(qū)別和用法

可以看到,沒有問題,那么我們從中人為的制造一些問題呢?

操作錯(cuò)誤



類型注釋
idint(11) 自動(dòng)增量
moneyint(11) unsigned [0]
titlevarchar(500) NULL

這里我們把 money 字段變成了無符號,即不能小于 0,并且,調(diào)整數(shù)據(jù)庫中的數(shù)據(jù)如下。

`SELECT * FROM `user` LIMIT 50` (0.000 秒)
修改idmoneytitle
編輯110000A
編輯20B

接著執(zhí)行下面的 SQL

select version();
SET AUTOCOMMIT=0;
begin;
select * from user where title in ('A','B') for update;
update user set  money = money + 1000 where title = 'A';
update user set money = money - 1000 where title = 'B';
select * from user where title in ('A','B');
commit;

MySQL和Redis事務(wù)的區(qū)別和用法

問題出現(xiàn)了,這里報(bào)出了錯(cuò)誤,但是可以看到 前面的 SQL 已經(jīng)是已執(zhí)行的了,結(jié)果已經(jīng)發(fā)生了變化,從這里看,似乎和 Redis 的處理差不多,除了錯(cuò)誤之后語句繼續(xù)執(zhí)行。但是 值的注意的是, 在我們實(shí)際開發(fā)中,這種情況程序會直接拋出異常,以供我們在 catch 塊中執(zhí)行 rollback ,以回滾操作確保數(shù)據(jù)完整,即使是單獨(dú)使用 MySQL 命令行 我們也可以用存儲過程來對異常進(jìn)行回滾。

語法錯(cuò)誤

剛剛看到 Redis 當(dāng)遇到 語法錯(cuò)誤 時(shí)會自動(dòng)丟棄事務(wù),阻止提交,那 MySQL 呢?

MySQL和Redis事務(wù)的區(qū)別和用法

答案:不會,MySQL 在順序執(zhí)行時(shí),如果未對異常進(jìn)行處理,總會將成功執(zhí)行的的提交,而不會觸發(fā)自動(dòng)終止,但是我們可以在程序執(zhí)行時(shí)進(jìn)行放棄提交。

Redis 為什么沒有回滾?

Redis 的官方文檔給出了這樣的解釋

// 只有在使用錯(cuò)誤的語法調(diào)用時(shí)才會失敗Redis命令(并且在命令排隊(duì)期間無法檢測到問題),或者對于持有錯(cuò)誤數(shù)據(jù)類型的鍵,Redis命令可能會失?。哼@意味著實(shí)際上失敗的命令是編程錯(cuò)誤的結(jié)果,以及在開發(fā)過程中很可能檢測到的一種錯(cuò)誤,而不是在生產(chǎn)中。

  • Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, and not in production.

// Redis內(nèi)部簡化且速度更快,因?yàn)樗恍枰貪L的能力。

  • Redis is internally simplified and faster because it does not need the ability to roll back.
  • 以上關(guān)于MySQL和Redis事務(wù)的區(qū)別和用法詳細(xì)內(nèi)容,對大家有幫助嗎?如果想要了解更多相關(guān),可以繼續(xù)關(guān)注我們的行業(yè)資訊板塊。 

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI