ACID屬性說明
原子性(Atomicity)
事務中的全部操作在資料庫中是不可分割的,要麼全部完成,要麼全部不執行。
一致性(Consistency)
交易的執行使資料從一個狀態轉換為另一個狀態,在交易開始之前和交易結束之後,資料庫的完整性約束沒有被破壞。
隔離性(Isolation)
交易的隔離性要求每個讀寫交易的物件對其他交易的操作物件相互分離,即該交易提交前對其他交易都不可見。
持久性(Durability)
資料庫執行交易後,資料的修改要被持久化保存下來。當資料庫重啟後,資料的值需要是被修改後的值。
Redis如何實作事務
實作原則
Redis交易的執行包含了三個步驟,具體如下:
- ##客戶端使用MULTI指令明確地開啟一個交易。
- 伺服器端接收到客戶端發送的特定操作(例如增刪改資料),並在交易中執行。這些操作就是Redis 本身提供的資料讀寫指令,雖然這些指令被客戶端傳送到了伺服器端,但是Redis實例只是把這些指令暫存到一個指令佇列中,並不會立即執行。
- 只有在收到 EXEC 指令並執行時,Redis才會提交交易並實際執行交易佇列中的所有指令。
事務相關指令
- MULTI :開啟交易
- EXEC:提交事務,執行指令隊列中所有的操作命令。
- DISCARD:放棄一個事務,清空命令佇列,但是無法支援交易的回溯。
- WATCH:偵測一個或多個鍵的值在交易執行的期間是否發生變化,如果發生變化,那麼當前交易放棄執行。
Redis的事務如何支援ACID
Redis事務的支援原子性嗎?
- 情況一:執行事務在入隊時就報錯,那麼Redis會放棄事務執行,從而保證事務原子性。
- 情況二:指令在入隊時沒報錯,但實際執行時卻報錯,無法保證事務原子性。
情況一範例說明
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set t1 v1
QUEUED
127.0.0.1:6379> set t2 v2
QUEUED
127.0.0.1:6379> setget t3
(error) ERR unknown command 'setget'
127.0.0.1:6379> set t4 v4
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get t4
(nil)
登入後複製
說明:在執行exec指令之前,如果發生語法錯誤(使用了不存在的指令),那麼指令入隊時, Redis就會報錯並且記錄錯誤,等到執行Exec命令之後,Redi會拒絕所有提交的命令,事務執行失敗。這種情況Reids的事務是可以支援原子性。
情況二範例說明
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr s2
QUEUED
127.0.0.1:6379> set a1 v1
QUEUED
127.0.0.1:6379> set a2 v2
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get a2
"v2"
登入後複製
說明: s2的值為v2,當執行incr指令時報報錯,因為incr只能新增integer的型別值,但是這種情況下我們發現Redis的事務沒有進行回滾,後面的指令能夠執行成功,所以這種情況下式無法保證事務的原子性。
Redis交易的支援一致性嗎?
情況一:命令入隊時就報錯
針對第一種情況,事務本身就會被放棄執行,所以可以保證事務的一致性。
情況二:命令入隊時沒報錯,實際執行時報錯
針對第二種情況,有錯誤的命令不會被執行,正確的命令可以正常執行,也不會改變資料庫的一致性。
情況三:Exec執行指令Redis實例發生故障
- 如果Redis持久化設定為RDB,那麼產生RDB快照不會在交易執行時執行,所以交易指令操作的結果不會被儲存到RDB快照中,使用RDB快照進行復原時,資料庫裡的資料也是一致的。
- 如果Reids持久化設定為AOF,而事務操作還沒有被記錄到AOF日誌時,實例就發生了故障,那麼,使用AOF日誌復原的資料庫資料是一致的。如果只有部分操作被記錄到了AOF日誌,我們可以使用 redis-check-aof 清除交易中已經完成的操作,資料庫復原後也是一致的。
Redis交易的支援隔離性嗎?
為了實現Redis的交易隔離性,需要使用watch指令。 Watch的原理是,在事務執行前,監控一個或多個鍵的變化時,當交易呼叫EXEC指令執行時,WATCH機制會先檢查監控的鍵是否被其它客戶端修改了。如果修改了監聽的值,就放棄事務執行,避免事務的隔離性被破壞。
範例說明
客戶端1:
127.0.0.1:6379> get blance
"100"
127.0.0.1:6379> watch blance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby blance 10
QUEUED
127.0.0.1:6379> incrby blance 10
QUEUED
127.0.0.1:6379> exec
(nil)
登入後複製
客戶端2:
127.0.0.1:6379> get blance
"100"
127.0.0.1:6379> set blance 90
OK
127.0.0.1:6379> get blance
"90"
登入後複製
說明:客戶端1使用watch偵測balance,開啟交易後,在客戶端2執行更改balance的值操作,模擬其他客戶端在事務執行期間更改watch監控的數據,然後再執行客戶端1的EXEC命令,發現事務未成功執行。
Redis事務的支援持久性嗎?
Redis的事務無法支援持久性,如果Redis使用了RDB模式,一個事務執行後,當下一次的RDB快照還未執行前,Redis發生了實例宕機,那麼這種情況下,事務修改的資料是無法保證持久化的,如果Redis採用AOF模式,如論持久化配置為no、everysec和always都可能會存在資料遺失,所以,不管Redis採用那種持久化模式,事務的持久性都無法支援。
以上是Redis事務如何實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!