事務(wù)的定義

事務(wù)是一組具備原子性操作的命令集合。在這一組命令中,要么全部執(zhí)行成功,要么全部執(zhí)行失敗。

事務(wù)的特點(diǎn)

  1. 原子性。原子性指的是事務(wù)操作具備原子操作,一個(gè)事務(wù)里面的 SQL 操作要么全部成功要么全部失敗,不能存在一些 SQL 成功,一些 SQL 執(zhí)行失敗。
  2. 隔離性。隔離性指的是多個(gè)事務(wù)之間是相互隔離的,事務(wù)之間是互不受影響的。
  3. 持久性。持久性指的是事務(wù)一旦提交,就不能進(jìn)行回滾(撤回),永久的保存在磁盤中。
  4. 一致性。一致性指的是事務(wù)操作前后必須滿足業(yè)務(wù)約束。

有關(guān)事務(wù)的四大特性的具體講解可以參考該文章
http://mindoc.qqdeveloper.com/docs/mysql/mysql-1cj2eksj770bg

Redis事務(wù)執(zhí)行邏輯

Redis在事務(wù)中的命令是添加到一個(gè)命令隊(duì)列里面,等待事務(wù)提交之后,則一一執(zhí)行命令隊(duì)列里面的命令。

Redis事務(wù)命令

  1. multi:開(kāi)啟事務(wù)。
  2. exec:提交當(dāng)前事務(wù)。
  3. discard:取消當(dāng)前事務(wù)。
  4. watch:監(jiān)聽(tīng)key是否在事務(wù)開(kāi)啟之前被其他命令修改,如果被修改去不處理事務(wù)內(nèi)的操作。
  5. unwatch:取消監(jiān)聽(tīng)key是否在事務(wù)開(kāi)啟之前被其他的命令修改。

命令演示

  1. 事務(wù)執(zhí)行流程。

客戶端一:負(fù)責(zé)開(kāi)啟事務(wù)并寫入緩存數(shù)據(jù)。

127.0.0.1:6379> multiOK127.0.0.1:6379> set user:id:1 1QUEUED127.0.0.1:6379> exec1) OK

事務(wù)執(zhí)行exec命令返回的是,事務(wù)中執(zhí)行的命令數(shù)量以及對(duì)應(yīng)的結(jié)果。

客戶端二:負(fù)責(zé)讀取緩存中的數(shù)據(jù)。

# 客戶端一執(zhí)行set之后,執(zhí)行exec之前。127.0.0.1:6379> get user:id:1(nil)# 客戶端執(zhí)行exec之后。127.0.0.1:6379> get user:id:1"1"
  1. watch對(duì)key監(jiān)聽(tīng)。

客戶端一:負(fù)責(zé)開(kāi)啟事務(wù),并使用watch監(jiān)聽(tīng)key。

# 監(jiān)聽(tīng)key之前查看值127.0.0.1:6379> get age"1"# 開(kāi)啟監(jiān)聽(tīng)127.0.0.1:6379> watch ageOK# 開(kāi)啟事務(wù)127.0.0.1:6379> multiOK# 修改被監(jiān)聽(tīng)的key值127.0.0.1:6379> set age 2QUEUED# 提交事務(wù)(發(fā)現(xiàn)返回的是nil,表示未執(zhí)行成功。)127.0.0.1:6379> exec(nil)# 重新獲取監(jiān)聽(tīng)的key值127.0.0.1:6379> get age"3"

客戶端二:負(fù)責(zé)修改客戶端一中監(jiān)聽(tīng)的key。

# 在客戶端一執(zhí)行watch命令,開(kāi)啟事務(wù)之后,提交事務(wù)之前執(zhí)行。127.0.0.1:6379> set age 3OK# 在客戶端一執(zhí)行exec命令之后執(zhí)行。127.0.0.1:6379> get age"3"

通過(guò)2中的演示,你會(huì)發(fā)現(xiàn)在事務(wù)開(kāi)啟之前對(duì)key做了監(jiān)聽(tīng)。事務(wù)正常提交之后,被監(jiān)聽(tīng)的key在事務(wù)中執(zhí)行的命令是不會(huì)被執(zhí)行的。unwatch對(duì)監(jiān)聽(tīng)的key,取消監(jiān)聽(tīng)事件。此時(shí)的取消監(jiān)聽(tīng)不能放在事務(wù)中,只能在事務(wù)開(kāi)啟之前對(duì)key的監(jiān)聽(tīng)事件做取消。 事務(wù)命令異常處理

事務(wù)原子性演示

  1. 命令錯(cuò)誤的原子性。
127.0.0.1:6379> multiOK127.0.0.1:6379> set user:name zhangsanQUEUED127.0.0.1:6379> set user:age 1QUEUED127.0.0.1:6379> set user:sex maxQUEUED# 執(zhí)行一條命令錯(cuò)誤的操作127.0.0.1:6379> set a(error) ERR wrong number of arguments for set command# 提交事務(wù)127.0.0.1:6379> exec(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> keys *1) "user:id:1"2) "name"3) "age"

通過(guò)上面的演示,在事務(wù)中執(zhí)行一條錯(cuò)誤的語(yǔ)法命令,整個(gè)事務(wù)都將不會(huì)被執(zhí)行。

  1. 內(nèi)部語(yǔ)法使用錯(cuò)誤。
127.0.0.1:6379> get name"zhangsan"127.0.0.1:6379> multiOK127.0.0.1:6379> set mu:id 1QUEUED# 執(zhí)行一個(gè)語(yǔ)法不當(dāng)?shù)牟僮?27.0.0.1:6379> incr nameQUEUED127.0.0.1:6379> set mu:age 2QUEUED127.0.0.1:6379> exec1) OK2) (error) ERR value is not an integer or out of range3) OK

通過(guò)上面的演示,在事務(wù)中執(zhí)行了一條語(yǔ)法不當(dāng)?shù)牡牟僮?,最終提交事務(wù)后。事務(wù)中的正確命令依舊不被執(zhí)行了。這不符合事務(wù)原子性的特點(diǎn)。

  1. 事務(wù)原子性總結(jié)。

    a. 當(dāng)事務(wù)中存在語(yǔ)法使用不當(dāng)?shù)那闆r時(shí),事務(wù)會(huì)跳過(guò)當(dāng)前的命令。其他的正確命令依舊被執(zhí)行。

    b. Redis中的事務(wù)并非一定滿足原子性的特點(diǎn)。

    c. 在事務(wù)中,執(zhí)行的命令,Redis只會(huì)檢測(cè)是否是一個(gè)合法的命令。如果合法則添加到命令隊(duì)列,如果不合法則直接阻止整個(gè)事務(wù)的執(zhí)行。

常見(jiàn)問(wèn)題總結(jié)

MySQL中的事務(wù)與Redis事務(wù)的區(qū)別

  1. Redis事務(wù)與Mysql事務(wù)我們知道關(guān)系性數(shù)據(jù)庫(kù)Mysql中具有事務(wù)的四大特性:「原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)」。

  2. 但是Redis的事務(wù)為了保證Redis除了客戶端的請(qǐng)求高效,去除了傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)的「事務(wù)回滾、加鎖、解鎖」這些消耗性能的操作,Redis的事務(wù)實(shí)現(xiàn)簡(jiǎn)單。

  3. 原子性中Redis的事務(wù)只能保證單個(gè)命令的原子性,多個(gè)命令就無(wú)法保證,如上面索道的運(yùn)行時(shí)錯(cuò)誤,即使中間有運(yùn)行時(shí)錯(cuò)誤出現(xiàn)也會(huì)正確的執(zhí)行后面正確的命令,不具有回滾操作。

  4. 既然沒(méi)有了原子性,數(shù)據(jù)的一致性也就無(wú)法保證,這些都需要程序員自己手動(dòng)去實(shí)現(xiàn)。Reids在進(jìn)行事務(wù)的時(shí)候,不會(huì)被中斷知道事務(wù)的運(yùn)行結(jié)束,也具有一定的隔離性,并且Redis也能持久化數(shù)據(jù)。