欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL學(xué)習(xí)之事務(wù)詳解

 更新時間:2022年12月08日 09:32:07   作者:榮·  
在數(shù)據(jù)庫中?事務(wù)(transaction)?可以把多個SQL給打包到一起,?即將多個SQL語句變成一個整體,?也就是說一個事務(wù)中的所有操作要么全部成功執(zhí)行,?要么完全不執(zhí)行.本文主要來和大家聊聊事務(wù)的使用,需要的可以參考一下

一. 事務(wù)的業(yè)務(wù)場景

在數(shù)據(jù)庫中 事務(wù)(transaction) 可以把多個SQL給打包到一起, 即將多個SQL語句變成一個整體, 也就是說一個事務(wù)中的所有操作要么全部成功執(zhí)行, 要么完全不執(zhí)行.

通過實(shí)際場景來理解事務(wù):

實(shí)際生活中我們經(jīng)常涉及轉(zhuǎn)帳操作, 張三給李四轉(zhuǎn)賬2000元, 涉及到兩個操作

  • 給張三的賬戶余額減去2000元
  • 給李四的賬戶余額增加2000元

這里就要考慮到這兩個操作的完整性, 也就是不能出現(xiàn)張三的賬戶余額減少了2000元, 但李四的賬戶余額未發(fā)生變化, 這就要求上面的兩個操作要么全部執(zhí)行完成功轉(zhuǎn)賬, 要么一個都不執(zhí)行雙方都沒有損失, 不會出現(xiàn)中途發(fā)生一些問題導(dǎo)致數(shù)據(jù)不一致的情況.

這樣的一次完整操作叫做 事務(wù)(transaction), 一個事務(wù)中的所有操作要么全部成功執(zhí)行, 要么完全不執(zhí)行.

二. 事務(wù)的使用

事務(wù)是如何保證操作的完整性的呢?

其實(shí)事務(wù)執(zhí)行中間出錯了, 只需要讓事務(wù)中的這些操作恢復(fù)成之前的樣子即可, 這里涉及到的一個操作, 回滾(rollback).

事務(wù)處理是一種對必須整批執(zhí)行的 MySQL 操作的管理機(jī)制, 在事務(wù)過程中, 除非整批操作全部正確執(zhí)行, 否則中間的任何一個操作出錯, 都會回滾 (rollback)到最初的安全狀態(tài)以確保不會對系統(tǒng)數(shù)據(jù)造成錯誤的改動.

相關(guān)語法:

-- 開啟事務(wù)
start transaction;

-- 若干條執(zhí)行sql

-- 提交/回滾事務(wù)
commit/rollback;

注意:

在開啟事務(wù)之后, 執(zhí)行sql不會立即去執(zhí)行, 只有等到commit操作后才會統(tǒng)一執(zhí)行(保證原子性).

示例:

首先創(chuàng)建一個賬戶表并初始化數(shù)據(jù)

-- 創(chuàng)建一個賬戶表
create table account(
     id int primary key auto_increment,
     name varchar(20),
     money double(10,2)
);
-- 初始化賬戶信息
insert into account(name, money) values ('張三', 10000), ('李四', 10000);

首先看正常情況下的轉(zhuǎn)賬操作

-- 張三賬戶 -2000
mysql> update account set money = money - 2000 where name = '張三';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 李四賬戶 +2000
mysql> update account set money = money + 2000 where name = '李四';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 轉(zhuǎn)賬成功
mysql> select * from account;
+----+--------+----------+
| id | name   | money    |
+----+--------+----------+
|  1 | 張三   |  8000.00 |
|  2 | 李四   | 12000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

如果操作中出現(xiàn)異常情況, 比如sql語句中所寫的注釋格式錯誤導(dǎo)致sql執(zhí)行中斷.

-- 先將張三和李四的賬戶余額恢復(fù)為10000元
update account set money = 10000 where name = '張三';
update account set money = 10000 where name = '李四';
-- 張三 -2000
mysql> update account set money = money - 2000 where name = '張三';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 李四 +2000
mysql> 沒加--的注釋
    -> update account set money = money + 2000 where name = '李四';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '沒加--的注釋
update account set money = money + 2000 where name = '李四'' at line 1
-- 出現(xiàn)異常
mysql> select * from account;
+----+--------+----------+
| id | name   | money    |
+----+--------+----------+
|  1 | 張三   |  8000.00 |
|  2 | 李四   | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

觀察結(jié)果發(fā)現(xiàn)了張三的賬戶少了2000元, 但李四的賬戶余額并沒有增加, 在實(shí)際操作中這種涉及錢的操作發(fā)生這種失誤可能會造成很大的損失.

為了防止這種失誤的出現(xiàn)我們就可以使用事務(wù)來打包這些操作.

-- 先將張的賬戶余額恢復(fù)為10000元
update account set money = 10000 where name = '張三';
-- 開啟事務(wù)
start transaction;
-- 張三 -2000
mysql> update account set money = money - 2000 where name = '張三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 李四 -2000
mysql> 沒加--的注釋
    -> update account set money = money + 2000 where name = '李四';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '沒加--的注釋
update account set money = money + 2000 where name = '李四'' at line 1
-- 預(yù)期結(jié)果
mysql> select * from account;
+----+--------+----------+
| id | name   | money    |
+----+--------+----------+
|  1 | 張三   |  8000.00 |
|  2 | 李四   | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

觀察這里的結(jié)果發(fā)現(xiàn)在當(dāng)前的數(shù)據(jù)庫用戶查詢到的account表中的賬戶余額發(fā)生了變化,但開啟了事務(wù)之后在commit之前只是臨時的預(yù)操作并不會真的去修改表中的數(shù)據(jù);

可以退出數(shù)據(jù)庫再打開重新查詢表中數(shù)據(jù)或者切換用戶去查詢?nèi)ヲ?yàn)證表中數(shù)據(jù)是否發(fā)生改變, 這里就不作演示了.

發(fā)現(xiàn)操作結(jié)果異常之后, 當(dāng)前用戶需要恢復(fù)到事務(wù)之前的狀態(tài), 即進(jìn)行回滾操作.

-- 回滾事務(wù)
mysql> rollback;
Query OK, 0 rows affected (0.03 sec)
-- 驗(yàn)證回滾后的狀態(tài)
mysql> select * from account;
+----+--------+----------+
| id | name   | money    |
+----+--------+----------+
|  1 | 張三   | 10000.00 |
|  2 | 李四   | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

如果開啟事務(wù)之后發(fā)現(xiàn)預(yù)操作的結(jié)果是預(yù)期的效果, 此時我們就可以提交事務(wù), 當(dāng)我們提交完事務(wù)之后, 數(shù)據(jù)就是真的修改了, 也就是硬盤中存儲的數(shù)據(jù)真的改變了.

-- 開啟事務(wù)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 張三 -2000
mysql> update account set money = money - 2000 where name = '張三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 李四 +2000
mysql> update account set money = money + 2000 where name = '李四';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
-- 提交事務(wù)
mysql> commit;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from account;
+----+--------+----------+
| id | name   | money    |
+----+--------+----------+
|  1 | 張三   |  8000.00 |
|  2 | 李四   | 12000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

要注意事務(wù)也不是萬能的, 不能保證你刪表刪庫之后可以完全恢復(fù), 只是在適量的數(shù)據(jù)和操作下使用事務(wù)可以避免一些問題.

回滾(rollback)操作, 實(shí)際上是我們把事務(wù)中的操作再進(jìn)行逆操作, 前面是插入, 回滾就是刪除…

這些操作是有很大開銷的, 可以保存, 但不能夠無限保存, 最多是將正再執(zhí)行的事務(wù)保存下來, 額外的內(nèi)容就不好再保存了; 數(shù)據(jù)庫要是有幾十億條數(shù)據(jù), 占據(jù)了幾百G硬盤空間, 不可能去花費(fèi)幾個T甚至更多的空間用來記錄這些數(shù)據(jù)是如何來的.

三. 事務(wù)的特性(ACID)

1. 原子性(Atomicity)

一個事務(wù)是一個不可分割的最小單位, 事務(wù)中的所有操作要么全部成功, 要么全部失敗, 沒有中間狀態(tài).

原子性主要是通過事務(wù)日志中的回滾日志(undo log)來實(shí)現(xiàn)的, 當(dāng)事務(wù)對數(shù)據(jù)庫進(jìn)行修改時, InnoDB 會根據(jù)操作生成相反操作的 undo log, 比如說對 insert 操作, 會生成 delete 記錄, 如果事務(wù)執(zhí)行失敗或者調(diào)用了 rollback,就會根據(jù) undo log 的內(nèi)容恢復(fù)到執(zhí)行之前的狀態(tài).

事務(wù)的原子性, 也是事務(wù)的核心特性, 是事務(wù)的初心.

2. 一致性(Consistency)

事務(wù)執(zhí)行之前和執(zhí)行之后數(shù)據(jù)都是合法的一致性狀態(tài), 即使發(fā)生了異常, 也不會因?yàn)楫惓R茐臄?shù)據(jù)庫的完整性約束, 比如唯一性約束等.

事務(wù)執(zhí)行前/執(zhí)行后, 都得是數(shù)據(jù)合法的狀態(tài); 比如像上面的轉(zhuǎn)賬, 不能說轉(zhuǎn)的過程出錯了, 導(dǎo)致出現(xiàn)錢轉(zhuǎn)丟了的情況.

3. 持久性(Durability)

事務(wù)提交之后對數(shù)據(jù)的修改是持久性的, 即使數(shù)據(jù)庫宕機(jī)也不會丟失, 通過事務(wù)日志中的重做日志(redo log)來保證; 事務(wù)修改之前, 會先把變更信息預(yù)寫到 redo log 中, 如果數(shù)據(jù)庫宕機(jī), 恢復(fù)后會讀取 redo log 中的記錄來恢復(fù)數(shù)據(jù)(回滾).

事務(wù)產(chǎn)生的修改, 都是會寫入硬盤的, 程序重啟/主機(jī)重啟/掉電, 事務(wù)都可以正常工作, 保證修改是生效的.

4. 隔離性(Isolation)

這里的隔離性是指一個數(shù)據(jù)庫服務(wù)器, 同時執(zhí)行多個事務(wù)的時候, 事務(wù)之間的相互影響程度.

一個服務(wù)器, 可以同時給多個客戶端提供服務(wù), 這多個客戶端是并發(fā)執(zhí)行的關(guān)系, 多個客戶端就會有多個事務(wù), 多個事務(wù)同時去操作一個表的時候, 特別容易出現(xiàn)互相影響的問題.

如果隔離性越高, 就意味著事務(wù)之間的并發(fā)程度越低, 執(zhí)行效率越慢, 但是數(shù)據(jù)準(zhǔn)確性越高.

如果隔離性越低, 就意味著事務(wù)之間的并發(fā)程度越高, 執(zhí)行效率越快, 但是數(shù)據(jù)準(zhǔn)確性越低.

隔離性通過事務(wù)的隔離級別來定義, 并用鎖機(jī)制來保證寫操作的隔離性, 用 MVCC 來保證讀操作的隔離性.

四. 事務(wù)并發(fā)異常

在實(shí)際生產(chǎn)環(huán)境下, 可能會出現(xiàn)大規(guī)模并發(fā)請求的情況, 如果沒有妥善的設(shè)置事務(wù)的隔離級別, 就可能導(dǎo)致一些異常情況的出現(xiàn),最常見的幾種異常為臟讀(Dirty Read), 幻讀(Phantom Read)和不可重復(fù)讀(Unrepeatable Read).

1. 臟讀

一個事務(wù)讀取到了另外一個事務(wù)沒有提交的數(shù)據(jù)(讀寫的是同一份數(shù)據(jù)).

說詳細(xì)點(diǎn)就是當(dāng)一個事務(wù)正在訪問數(shù)據(jù)并且對數(shù)據(jù)進(jìn)行了修改, 而這種修改還沒有提交到數(shù)據(jù)庫中,與此同時時另外一個事務(wù)也訪問這個數(shù)據(jù), 然后使用了這個數(shù)據(jù); 因?yàn)檫@個數(shù)據(jù)是還沒有提交的數(shù)據(jù), 那么另外一個事務(wù)讀到的這個數(shù)據(jù)就是臟數(shù)據(jù), 依據(jù)臟數(shù)據(jù)所做的操作可能是不正確的.

用一個場景例子來理解, 張三正在寫代碼, 李四趴在屏幕前看張三寫代碼, 等張三走掉之后, 李四就把他剛剛寫的這段代碼刪掉了, 此時李四看到的這段代碼就可能是一個錯誤的代碼.

在這個場景下, 張三和李四就可以理解為兩個事務(wù), 這兩個事務(wù)是完全并發(fā)沒有任何限制的, 此時就會出現(xiàn)臟讀問題.

解決臟讀問題的辦法, 就是降低并發(fā)性, 提高隔離性, 具體來說就是給這里的 “寫操作” 加鎖, 張三在寫代碼的時候, 李四不能看, 張三和李四約定張三代碼寫完后會提交到githup上, 李四去githup上去看.

當(dāng)進(jìn)行了寫加鎖的時候, 張三寫的時候, 李四就不能同時去讀了; 相當(dāng)于降低了并發(fā)程度, 提高了隔離性. 降低了一定的效率, 但是提高了準(zhǔn)確性.

2. 不可重復(fù)讀

在同一事務(wù)中, 連續(xù)兩次讀取同一數(shù)據(jù), 得到的結(jié)果不一致.

還是基于上面的場景進(jìn)行理解, 上面已經(jīng)約定了寫加鎖(張三寫代碼過程中, 李四不要讀, 等到張三提交之后, 李四再去讀).

此時張三在寫代碼, 張三和李四有約定, 所以此時李四在等張三把代碼提交到githup上再去看代碼.

過了一會兒, 張三寫完了, 并將代碼提交到了githup上, 李四開始讀代碼.

當(dāng)李四正在讀這個代碼的時候, 張三覺得自己的代碼還有不足, 于是張三動手修改, 重新提交了個版本; 導(dǎo)致李四讀代碼讀了一半, 突然代碼自動就變了.

這種情況就是不可重復(fù)讀問題了, 解決辦法是給讀操作也加鎖, 張三在讀代碼的時候, 李四不能修改.

此時這兩個事務(wù)之間的并發(fā)程度進(jìn)一步降低了, 隔離性又進(jìn)一步提高了, 運(yùn)行速度又進(jìn)一步變慢了, 數(shù)據(jù)的準(zhǔn)確性又進(jìn)—步提高了.

3. 幻讀

同一事務(wù)中, 用同樣的操作讀取兩次, 得到的記錄數(shù)不相同.

幻讀是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時發(fā)生的一種現(xiàn)象, 例如第一個事務(wù)對一個表中的數(shù)據(jù)進(jìn)行了修改, 這種修改涉及到表中的全部數(shù)據(jù)行; 同時, 第二個事務(wù)也修改這個表中的數(shù)據(jù), 這種修改是向表中插入一行新數(shù)據(jù); 那么, 以后就會發(fā)生操作第一個事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行, 就好象發(fā)生了幻覺一樣.

再基于2中的場景進(jìn)行理解, 當(dāng)前已經(jīng)約定了寫加鎖和讀加鎖, 即張三寫代碼的時候, 李四不能讀; 李四讀代碼的時候, 張三也不能寫.

此時李四在讀代碼, 張三雖然不能去修改李四現(xiàn)在正在讀的這個文件, 但是李四又去新增/刪除一個其他的文件, 此時, 雖然李四讀的代碼內(nèi)容沒變, 但他發(fā)現(xiàn), 文件的數(shù)量變了; 這就是幻讀問題了.

解決幻讀問題的辦法是 串行化, 也就是徹底的舍棄并發(fā), 此時只要李四在讀代碼, 張三就不能進(jìn)行任何操作.

五. MySQL的四個隔離級別

MySQL中有 4 種事務(wù)隔離級別, 由低到高依次為 讀未提交 Read Uncommitted, 讀已提交 Read Committed , 可重復(fù)讀 Repeatable Read , 串行化 Serializable.

串行化的事務(wù)處理方式是最安全的, 但不能說用這個就一定好, 應(yīng)該是根據(jù)實(shí)際需求去選擇合適的隔離級別, 比如銀行等涉及錢的場景, 就需要確保準(zhǔn)確性, 速度慢一點(diǎn)也沒什么; 而比如抖音,B站,快手等上面的點(diǎn)贊數(shù), 收藏?cái)?shù)就沒必要那么精確了, 這個場景下速度提高一點(diǎn)體驗(yàn)會更好一些.

臟讀不可重復(fù)讀幻讀
讀未提交 read uncommited
讀已提交 read commited×
可重復(fù)讀 repeatable read××
串行化 serializable×××

read uncommited

不做任何限制, 事務(wù)之間都是隨意并發(fā)執(zhí)行的; 并發(fā)程度最高,隔離性最差.

會產(chǎn)生臟讀 + 不可重復(fù)讀 + 幻讀問題.

read commited

對寫操作加鎖, 并發(fā)程度降低, 隔離性提高.

解決了臟讀問題, 仍然存在不可重復(fù)讀 + 幻讀問題.

repeatable read

寫加鎖, 讀加鎖, 隔離性再次提高, 并發(fā)程度再次降低.

解決了臟讀 + 不可重復(fù)讀問題, 仍然存在幻讀問題.

這個隔離級別也是MySQL的默認(rèn)隔離級別, 如果需要改的話, 可以通過MySQL的配置文件來進(jìn)行調(diào)整.

serializable

嚴(yán)格執(zhí)行串行化, 并發(fā)程度最低, 隔離性最高, 執(zhí)行速度最慢.

解決了 臟讀 + 不可重復(fù)讀 + 幻讀問題.=

到此這篇關(guān)于MySQL學(xué)習(xí)之事務(wù)詳解的文章就介紹到這了,更多相關(guān)MySQL事務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mysql之如何把查詢的結(jié)果保存到新表

    mysql之如何把查詢的結(jié)果保存到新表

    這篇文章主要介紹了mysql之如何把查詢的結(jié)果保存到新表問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 淺談mysql的子查詢聯(lián)合與in的效率

    淺談mysql的子查詢聯(lián)合與in的效率

    本文是作者在實(shí)際產(chǎn)品測試中遇到的問題,繼而作了相關(guān)總結(jié),具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • MySql數(shù)據(jù)引擎簡介與選擇方法

    MySql數(shù)據(jù)引擎簡介與選擇方法

    在MySQL 5.1中,MySQL AB引入了新的插件式存儲引擎體系結(jié)構(gòu),允許將存儲引擎加載到正在運(yùn)新的MySQL服務(wù)器中
    2012-11-11
  • mysql中update和select結(jié)合使用方式

    mysql中update和select結(jié)合使用方式

    這篇文章主要介紹了mysql中update和select結(jié)合使用方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • CentOS7編譯安裝MySQL5.7.24的教程詳解

    CentOS7編譯安裝MySQL5.7.24的教程詳解

    這篇文章主要介紹了CentOS7編譯安裝MySQL5.7.24的教程,非常不錯,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-12-12
  • MySQL8.0升級的踩坑歷險(xiǎn)記

    MySQL8.0升級的踩坑歷險(xiǎn)記

    聽說mysql8的性能提升了很多,對于我這種喜歡把所有軟件升級到最新版的人來說,二話不說直接升級,這篇文章主要給大家介紹了關(guān)于MySQL8.0升級踩坑的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • mysql批量刪除大量數(shù)據(jù)

    mysql批量刪除大量數(shù)據(jù)

    這篇文章主要介紹了mysql批量刪除大量數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • MySQL中關(guān)于case when的用法

    MySQL中關(guān)于case when的用法

    這篇文章主要介紹了MySQL中關(guān)于case when的用法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • mysql Access denied for user ‘root’@’localhost’ (using password: YES)解決方法

    mysql Access denied for user ‘root’@’localhost’ (using passw

    這篇文章主要介紹了mysql Access denied for user ‘root’@’localhost’ (using password: YES)解決方法,本文給出詳細(xì)的解決步驟及操作注釋,需要的朋友可以參考下
    2015-07-07
  • MySQL隔離級別和鎖機(jī)制的深入講解

    MySQL隔離級別和鎖機(jī)制的深入講解

    這篇文章主要給大家介紹了關(guān)于MySQL隔離級別和鎖機(jī)制的相關(guān)資料,主要包括深入理解MySQL隔離級別和鎖機(jī)制使用實(shí)例、應(yīng)用技巧、基本知識點(diǎn)總結(jié)和需要注意事項(xiàng),需要的朋友可以參考下
    2021-08-08

最新評論