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

一篇文章帶你輕松了解MySQL之事務(wù)的簡介

 更新時間:2023年06月05日 10:05:58   作者:multis  
事務(wù)可以由一條非常簡單的SQL語句組成,也可以由一組復(fù)雜的SQL語句組成,事務(wù)的目的是將數(shù)據(jù)庫從一種一致性狀態(tài)轉(zhuǎn)換為另一種一致性狀態(tài),下面這篇文章主要給大家介紹了關(guān)于MySQL事務(wù)簡介的相關(guān)資料,需要的朋友可以參考下

前言:

事務(wù)(Transaction)是一組SQL組成的執(zhí)行單元(Unit),是數(shù)據(jù)庫并發(fā)控制和恢復(fù)回滾的基本單位。一個事務(wù)中可能包含多個SQL,要么都失敗,要么都成功,今天我們就詳細學(xué)習(xí)一下。

一、事務(wù)的起源

對于大部分程序員來說,他們的任務(wù)就是把現(xiàn)實世界的業(yè)務(wù)場景映射到數(shù)據(jù)庫世界。比如銀行為了存儲人們的賬戶信息會建立一個account表:

mysql> CREATE TABLE account (
    id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',
    name VARCHAR(100) COMMENT '客戶名稱',
    balance INT COMMENT '余額',
    PRIMARY KEY (id)
);
Query OK, 0 rows affected (0.04 sec)

張三和李四是一對好基友,他們都到銀行開一個賬戶,他們在現(xiàn)實世界中擁有的資產(chǎn)就會體現(xiàn)在數(shù)據(jù)庫世界的account表中。比如現(xiàn)在張三有11元,李四只有2元,那么現(xiàn)實中的這個情況映射到數(shù)據(jù)庫的account表就是這樣:

mysql> INSERT INTO account(name,balance) VALUES ('張三',11),('李四',2);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 張三   |      11 |
|  2 | 李四   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

在某個特定的時刻,張三李四這些家伙在銀行所擁有的資產(chǎn)是一個特定的值,這些特定的值也可以被描述為賬戶在這個特定的時刻現(xiàn)實世界的一個狀態(tài)。隨著時間的流逝,張三和李四可能陸續(xù)進行向賬戶中存錢、取錢或者向別人轉(zhuǎn)賬等操作,這樣他們賬戶中的余額就可能發(fā)生變動,每一個操作都相當于現(xiàn)實世界中賬戶的一次狀態(tài)轉(zhuǎn)換。數(shù)據(jù)庫世界作為現(xiàn)實世界的一個映射,當然也要進行相應(yīng)的變動。不變不知道,一變嚇一跳,現(xiàn)實世界中一些看似很簡單的狀態(tài)轉(zhuǎn)換,映射到數(shù)據(jù)庫世界卻不是那么容易的。比方說有一次李四需要10元錢,急忙打電話給張三要借10塊錢,現(xiàn)實世界中的張三走向了ATM機,輸入了李四的賬號以及10元的轉(zhuǎn)賬金額,然后按下確認,張三就拔卡走人了。對于數(shù)據(jù)庫世界來說,相當于執(zhí)行了下邊這兩條語句:

mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE account SET balance = balance + 10 WHERE id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

但是這里頭有個問題,上述兩條語句只執(zhí)行了一條時忽然服務(wù)器斷電了咋辦?把張三的錢扣了,但是沒給李四轉(zhuǎn)過去~ 即使對于單獨的一條語句,我們前邊嘮叨Buffer Pool時也說過,在對某個頁面進行讀寫訪問時,都會先把這個頁面加載到Buffer Pool中,之后如果修改了某個頁面,也不會立即把修改同步到磁盤,而只是把這個修改了的頁面加到Buffer Poolflush鏈表中,在之后的某個時間點才會刷新到磁盤。如果在將修改過的頁刷新到磁盤之前系統(tǒng)崩潰了那豈不是李四還是沒錢?或者在刷新磁盤的過程中(只刷新部分數(shù)據(jù)到磁盤上)系統(tǒng)奔潰了李四也沒錢?

怎么才能保證讓可憐的李四有錢呢?其實再仔細想想,我們只是想讓某些數(shù)據(jù)庫操作符合現(xiàn)實世界中狀態(tài)轉(zhuǎn)換的規(guī)則而已,設(shè)計數(shù)據(jù)庫的大叔們仔細盤算了盤算,現(xiàn)實世界中狀態(tài)轉(zhuǎn)換的規(guī)則有好幾條,我們慢慢道來。

1.1 原子性(Atomicity)

現(xiàn)實世界中轉(zhuǎn)賬操作是一個不可分割的操作,也就是說要么壓根就沒轉(zhuǎn),要么轉(zhuǎn)賬成功,不能存在中間的狀態(tài),也就是轉(zhuǎn)了一半的這種情況。設(shè)計數(shù)據(jù)庫的時候把這種要么全做,要么全不做的規(guī)則稱之為原子性。但是在現(xiàn)實世界中的一個不可分割的操作卻可能對應(yīng)著數(shù)據(jù)庫世界若干條不同的操作,數(shù)據(jù)庫中的一條操作也可能被分解成若干個步驟(比如先修改緩存頁,之后再刷新到磁盤等),最要命的是在任何一個可能的時間都可能發(fā)生意想不到的錯誤(可能是數(shù)據(jù)庫本身的錯誤,或者是操作系統(tǒng)錯誤,甚至是直接斷電之類的)而使操作執(zhí)行不下去,所以李四可能也沒錢。為了保證在數(shù)據(jù)庫世界中某些操作的原子性,設(shè)計數(shù)據(jù)庫的時候需要費一些心機來保證如果在執(zhí)行操作的過程中發(fā)生了錯誤,把已經(jīng)做了的操作恢復(fù)成沒執(zhí)行之前的樣子,這也是我們后邊章節(jié)要仔細嘮叨的內(nèi)容。

1.2 隔離性(Isolation)

現(xiàn)實世界中的兩次狀態(tài)轉(zhuǎn)換應(yīng)該是互不影響的,比如說張三向李四同時進行的兩次金額為5元的轉(zhuǎn)賬(假設(shè)可以在兩個ATM機上同時操作)。那么最后張三的賬戶里肯定會少10元,李四的賬戶里肯定多了10元。但是到對應(yīng)的數(shù)據(jù)庫世界中,事情又變的復(fù)雜了一些。為了簡化問題,我們粗略的假設(shè)張三向李四轉(zhuǎn)賬5元的過程是由下邊幾個步驟組成的:

  • 步驟一:讀取張三賬戶的余額到變量A中,這一步驟簡寫為read(A)
  • 步驟二:將張三賬戶的余額減去轉(zhuǎn)賬金額,這一步驟簡寫為A = A - 5
  • 步驟三:將張三賬戶修改過的余額寫到磁盤里,這一步驟簡寫為write(A)
  • 步驟四:讀取李四賬戶的余額到變量B,這一步驟簡寫為read(B)
  • 步驟五:將李四賬戶的余額加上轉(zhuǎn)賬金額,這一步驟簡寫為B = B + 5
  • 步驟六:將李四賬戶修改過的余額寫到磁盤里,這一步驟簡寫為write(B)

我們將張三向李四同時進行的兩次轉(zhuǎn)賬操作分別稱為T1T2,在現(xiàn)實世界中T1T2是應(yīng)該沒有關(guān)系的,可以先執(zhí)行完T1,再執(zhí)行T2,或者先執(zhí)行完T2,再執(zhí)行T1,對應(yīng)的數(shù)據(jù)庫操作就像這樣:

但是很不幸,真實的數(shù)據(jù)庫中T1T2的操作可能交替執(zhí)行,比如這樣:

如果按照上圖中的執(zhí)行順序來進行兩次轉(zhuǎn)賬的話,最終張三的賬戶里還剩6元錢,相當于只扣了5元錢,但是李四的賬戶里卻成了12元錢,相當于多了10元錢,這銀行豈不是要虧死了?

所以對于現(xiàn)實世界中狀態(tài)轉(zhuǎn)換對應(yīng)的某些數(shù)據(jù)庫操作來說,不僅要保證這些操作以原子性的方式執(zhí)行完成,而且要保證其它的狀態(tài)轉(zhuǎn)換不會影響到本次狀態(tài)轉(zhuǎn)換,這個規(guī)則被稱之為隔離性。這時設(shè)計數(shù)據(jù)庫的大叔們就需要采取一些措施來讓訪問相同數(shù)據(jù)(上例中的A賬戶和B賬戶)的不同狀態(tài)轉(zhuǎn)換(上例中的T1和T2)對應(yīng)的數(shù)據(jù)庫操作的執(zhí)行順序有一定規(guī)律,這也是我們后邊章節(jié)要仔細嘮叨的內(nèi)容。

1.3 一致性(Consistency)

我們生活的這個世界存在著形形色色的約束,比如身份證號不能重復(fù),性別只能是男或者女,高考的分數(shù)只能在0~750之間,人民幣面值最大只能是100,紅綠燈只有3種顏色,房價不能為負的,學(xué)生要聽老師話,吧啦吧啦有點兒扯遠了~ 只有符合這些約束的數(shù)據(jù)才是有效的,比如有個小孩兒跟你說他高考考了1000分,你一聽就知道他胡扯呢。數(shù)據(jù)庫世界只是現(xiàn)實世界的一個映射,現(xiàn)實世界中存在的約束當然也要在數(shù)據(jù)庫世界中有所體現(xiàn)。如果數(shù)據(jù)庫中的數(shù)據(jù)全部符合現(xiàn)實世界中的約束(all defined rules),我們說這些數(shù)據(jù)就是一致的,或者說符合一致性的。

如何保證數(shù)據(jù)庫中數(shù)據(jù)的一致性(就是符合所有現(xiàn)實世界的約束)呢?這其實靠兩方面的努力:

方面一: 數(shù)據(jù)庫本身能為我們保證一部分一致性需求(就是數(shù)據(jù)庫當身可以保證一部分現(xiàn)實世界的約束永遠有效)。

我們知道MySQL數(shù)據(jù)庫可以為表建立主鍵、唯一索引、外鍵、聲明某個列為NOT NULL來拒絕NULL值的插入。比如說當我們對某個列建立唯一索引時,如果插入某條記錄時該列的值重復(fù)了,那么MySQL就會報錯并且拒絕插入。除了這些我們已經(jīng)非常熟悉的保證一致性的功能,MySQL還支持CHECK語法來當定義約束,比如這樣:

CREATE TABLE account (
    id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',
    name VARCHAR(100) COMMENT '客戶名稱',
    balance INT COMMENT '余額',
    PRIMARY KEY (id),
    CHECK (balance >= 0)
);

上述例子中的CHECK語句本意是想規(guī)定balance列不能存儲小于0的數(shù)字,對應(yīng)的現(xiàn)實世界的意思就是銀行賬戶余額不能小于0。但是很遺憾,MySQL僅僅支持 CHECK語法,但實際上并沒有一點卵用,也就是說即使我們使用上述帶有CHECK子句的建表語句來創(chuàng)建account表,那么在后續(xù)插入或更新記錄時,MySQL并不會去檢查CHECK子句中的約束是否成立。

小提示:
其它的一些數(shù)據(jù)庫,比如SQL Server或者Oracle支持的CHECK語法是有實實在在的作用的,每次進行插入或更新記錄之前都會檢查一下數(shù)據(jù)是否符合CHECK子句中指定的約束條件是否成立,如果不成立的話就會拒絕插入或更新。

雖然CHECK子句對一致性檢查沒什么卵用,但是我們還是可以通過定義觸發(fā)器的方式來當定義一些約束條件以保證數(shù)據(jù)庫中數(shù)據(jù)的一致性。

方面二: 更多的一致性需求需要靠寫業(yè)務(wù)代碼的程序員當己保證。

為建立現(xiàn)實世界和數(shù)據(jù)庫世界的對應(yīng)關(guān)系,理論上應(yīng)該把現(xiàn)實世界中的所有約束都反應(yīng)到數(shù)據(jù)庫世界中,但是很不幸,在更改數(shù)據(jù)庫數(shù)據(jù)時進行一致檢查是一個耗費性能的?作,比方說我們?yōu)?code>account表建立了一個觸發(fā)器,每當插入或者更新記錄時都會校驗一下balance列的值是不是大于0,這就會影響到插入或更新的速度。僅僅是校驗一行記錄符不符合一致性需求倒也不是什么大問題,有的一致性需求簡直變態(tài),比方說銀行會建立一張代表賬單的表,里邊兒記錄了每個賬戶的每筆交易,每一筆交易完成后,都需要保證整個系統(tǒng)的余額等于所有賬戶的收入減去所有賬戶的支出。如果在數(shù)據(jù)庫層面實現(xiàn)這個一致性需求的話,每次發(fā)生交易時,都需要將所有的收入加起來減去所有的支出,再將所有的賬戶余額加起來,看看兩個值相不相等。這不是搞笑呢么,如果賬單表里有幾億條記錄,光是這個校驗的過程可能就要跑好幾個小時,也就是說你在煎餅攤買個煎餅,使用銀行卡付款之后要等好幾個小時才能提示付款成功,這樣的性能代價是完全承受不起的。

現(xiàn)實生活中復(fù)雜的一致性需求比比皆是,而由于性能問題把一致性需求交給數(shù)據(jù)庫去解決這是不現(xiàn)實的,所以這個鍋就甩給了業(yè)務(wù)端程序員。比方說我們的account表,我們也可以不建立觸發(fā)器,只要編寫業(yè)務(wù)的程序員在當己的業(yè)務(wù)代碼里判斷一下,當某個操作會將balance列的值更新為小于0的值時,就不執(zhí)行該操作就好了嘛!

我們前邊嘮叨的原子性和隔離性都會對一致性產(chǎn)生影響,比如我們現(xiàn)實世界中轉(zhuǎn)賬操作完成后,有一個一致性需求就是參與轉(zhuǎn)賬的賬戶的總的余額是不變的。如果數(shù)據(jù)庫不遵循原子性要求,也就是轉(zhuǎn)了一半就不轉(zhuǎn)了,也就是說給張三扣了錢而沒給李四轉(zhuǎn)過去,那最后就是不符合一致性需求的;類似的,如果數(shù)據(jù)庫不遵循隔離性要求,就像我們前邊嘮叨隔離性時舉的例子中所說的,最終張三賬戶中扣的錢和李四賬戶中漲的錢可能就不一樣了,也就是說不符合一致性需求了。所以說,數(shù)據(jù)庫某些操作的原子性和隔離性都是保證一致性的一種手段,在操作執(zhí)行完成后保證符合所有既定的約束則是一種結(jié)果。那滿足原子性和隔離性的操作一定就滿足一致性么?那倒也不一定,比如說張三要轉(zhuǎn)賬20元給李四,雖然在滿足原子性和隔離性,但轉(zhuǎn)賬完成了之后張三的賬戶的余額就成負的了,這顯然是不滿足一致性的。那不滿足原子性和隔離性的操作就一定不滿足一致性么?這也不一定,只要最后的結(jié)果符合所有現(xiàn)實世界中的約束,那么就是符合一致性的。

1.4 持久性(Durability)

當現(xiàn)實世界的一個狀態(tài)轉(zhuǎn)換完成后,這個轉(zhuǎn)換的結(jié)果將永久的保留,這個規(guī)則被設(shè)計數(shù)據(jù)庫的大叔們稱為持久性。比方說張三向李四轉(zhuǎn)賬,當ATM機提示轉(zhuǎn)賬成功了,就意味著這次賬戶的狀態(tài)轉(zhuǎn)換完成了,張三就可以拔卡走人了。如果當張三走掉之后,銀行又把這次轉(zhuǎn)賬操作給撤銷掉,恢復(fù)到?jīng)]轉(zhuǎn)賬之前的樣子,那李四還是沒錢,所以這個持久性是非常重要的。當把現(xiàn)實世界的狀態(tài)轉(zhuǎn)換映射到數(shù)據(jù)庫世界時,持久性意味著該轉(zhuǎn)換對應(yīng)的數(shù)據(jù)庫操作所修改的數(shù)據(jù)都應(yīng)該在磁盤上保留下來,不論之后發(fā)生了什么事故,本次轉(zhuǎn)換造成的影響都不應(yīng)該被丟失掉。

二、事務(wù)的概念

為了方便大家記住我們上邊嘮叨的現(xiàn)實世界狀態(tài)轉(zhuǎn)換過程中需要遵守的4個特性,我們把原子性(Atomicity)、隔離性(Isolation)、一致性(Consistency)和持久性(Durability)這四個詞對應(yīng)的英文單詞首字母提取出來就是A、I、C、D,稍微變換一下順序可以組成一個完整的英文單詞:ACID。想必大家都是學(xué)過初高中英語的,ACID是英文酸的意思,以后我們提到ACID這個詞兒,大家就應(yīng)該想到原子性、一致性、隔離性、持久性這幾個規(guī)則。另外,設(shè)計數(shù)據(jù)庫的大叔為了方便起見,把需要保證原子性、隔離性、一致性和持久性的一個或多個數(shù)據(jù)庫操作稱之為一個事務(wù)(英文名是:transaction)。

我們現(xiàn)在知道事務(wù)是一個抽象的概念,它其實對應(yīng)著一個或多個數(shù)據(jù)庫操作,設(shè)計數(shù)據(jù)庫的大叔根據(jù)這些操作所執(zhí)行的不同階段把事務(wù)大致上劃分成了這么幾個狀態(tài):

  • 活動的(active)
    事務(wù)對應(yīng)的數(shù)據(jù)庫操作正在執(zhí)行過程中時,我們就說該事務(wù)處在活動的狀態(tài)。
  • 部分提交的(partially committed)
    當事務(wù)中的最后一個操作執(zhí)行完成,但由于操作都在內(nèi)存中執(zhí)行,所造成的影響并沒有刷新到磁盤時,我們就說該事務(wù)處在部分提交的狀態(tài)。
  • 失敗的(failed)
    當事務(wù)處在活動的或者部分提交的狀態(tài)時,可能遇到了某些錯誤(數(shù)據(jù)庫當身的錯誤、操作系統(tǒng)錯誤或者直接斷電等)而無法繼續(xù)執(zhí)行,或者人為的停止當前事務(wù)的執(zhí)行,我們就說該事務(wù)處在失敗的狀態(tài)。
  • 中止的(aborted)
    如果事務(wù)執(zhí)行了半截而變?yōu)槭〉臓顟B(tài),比如我們前邊嘮叨的張三向李四轉(zhuǎn)賬的事務(wù),當張三賬戶的錢被扣除,但是李四賬戶的錢沒有增加時遇到了錯誤,從而當前事務(wù)處在了失敗的狀態(tài),那么就需要把已經(jīng)修改的張三賬戶余額調(diào)整為未轉(zhuǎn)賬之前的金額,換句話說,就是要撤銷失敗事務(wù)對當前數(shù)據(jù)庫造成的影響。書面一點的話,我們把這個撤銷的過程稱之為回滾。當回滾操作執(zhí)行完畢時,也就是數(shù)據(jù)庫恢復(fù)到了執(zhí)行事務(wù)之前的狀態(tài),我們就說該事務(wù)處在了中止的狀態(tài)。
  • 提交的(committed)
    當一個處在部分提交的狀態(tài)的事務(wù)將修改過的數(shù)據(jù)都同步到磁盤上之后,我們就可以說該事務(wù)處在了提交的狀態(tài)。

隨著事務(wù)對應(yīng)的數(shù)據(jù)庫操作執(zhí)行到不同階段,事務(wù)的狀態(tài)也在不斷變化,一個基本的狀態(tài)轉(zhuǎn)換圖如下所示:

從圖中大家也可以看出了,只有當事務(wù)處于提交的或者中止的狀態(tài)時,一個事務(wù)的生命周期才算是結(jié)束了。對于已經(jīng)提交的事務(wù)來說,該事務(wù)對數(shù)據(jù)庫所做的修改將永久生效,對于處于中止狀態(tài)的事務(wù),該事務(wù)對數(shù)據(jù)庫所做的所有修改都會被回滾到?jīng)]執(zhí)行該事務(wù)之前的狀態(tài)。

小提示:
大家知道我們的計算機術(shù)語基本上全是從英文翻譯成中文的,事務(wù)的英文是transaction,英文直譯就是交易,買賣的意思,交易就是買的人付錢,賣的人交貨,不能付了錢不交貨,交了貨不付錢把,所以交易本身就是一種不可分割的操作。不知道是哪位大神把transaction翻譯成了事務(wù)(我想估計是他們也想不出什么更好的詞兒,只能隨便找一個了),事務(wù)這個詞兒完全沒有交易、買賣的意思,所以大家理解起來也會比較困難,外國人理解transaction可能更好理解一點吧~

三、MySQL中事務(wù)的語法

我們說事務(wù)的本質(zhì)其實只是一系列數(shù)據(jù)庫操作,只不過這些數(shù)據(jù)庫操作符合ACID特性而已,那么MySQL中如何將某些操作放到一個事務(wù)里去執(zhí)行的呢?我們下邊就來重點嘮叨嘮叨。

3.1 開啟事務(wù)

我們可以使用下邊兩種語句之一來開啟一個事務(wù):

語句一: BEGIN [WORK];

BEGIN語句代表開啟一個事務(wù),后邊的單詞WORK可有可無。開啟事務(wù)后,就可以繼續(xù)寫若干條語句,這些語句都屬于剛剛開啟的這個事務(wù)。

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事務(wù)的語句...

語句二: START TRANSACTION;

START TRANSACTION語句和BEGIN語句有著相同的功效,都標志著開啟一個事務(wù),比如這樣:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> 加入事務(wù)的語句...

不過比BEGIN語句牛逼一點兒的是,可以在START TRANSACTION語句后邊跟隨幾個修飾符,就是它們幾個:

  • READ ONLY:標識當前事務(wù)是一個只讀事務(wù),也就是屬于該事務(wù)的數(shù)據(jù)庫操作只能讀取數(shù)據(jù),而不能修改數(shù)據(jù)。

小提示:
其實只讀事務(wù)中只是不允許修改那些其他事務(wù)也能訪問到的表中的數(shù)據(jù),對于臨時表來說(我們使用CREATE TMEPORARY
TABLE創(chuàng)建的表),由于它們只能在當前會話中可見,所以只讀事務(wù)其實也是可以對臨時表進行增、刪、改操作的。

  • READ WRITE:標識當前事務(wù)是一個讀寫事務(wù),也就是屬于該事務(wù)的數(shù)據(jù)庫操作既可以讀取數(shù)據(jù),也可以修改數(shù)據(jù)。
  • WITH CONSISTENT SNAPSHOT:啟動一致性讀(先不用關(guān)心啥是個一致性讀,后邊的章節(jié)才會嘮叨)。

比如我們想開啟一個只讀事務(wù)的話,直接把READ ONLY這個修飾符加在START TRANSACTION語句后邊就好,比如這樣:

START TRANSACTION READ ONLY;

如果我們想在START TRANSACTION后邊跟隨多個修飾符的話,可以使用逗號將修飾符分開,比如開啟一個只讀事務(wù)和一致性讀,就可以這樣寫:

START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;

或者開啟一個讀寫事務(wù)和一致性讀,就可以這樣寫:

START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT

不過這里需要大家注意的一點是,READ ONLYREAD WRITE是用來設(shè)置所謂的事務(wù)訪問模式的,就是以只讀還是讀寫的方式來訪問數(shù)據(jù)庫中的數(shù)據(jù),一個事務(wù)的訪問模式不能同時既設(shè)置為只讀的也設(shè)置為讀寫的,所以我們不能同時把READ ONLYREAD WRITE放到START TRANSACTION語句后邊。另外,如果我們不顯式指定事務(wù)的訪問模式,那么該事務(wù)的訪問模式就是讀寫模式。

3.2 提交事務(wù)

開啟事務(wù)之后就可以繼續(xù)寫需要放到該事務(wù)中的語句了,當最后一條語句寫完了之后,我們就可以提交該事務(wù)了,提交的語句也很簡單:COMMIT [WORK]

COMMIT語句就代表提交一個事務(wù),后邊的WORK可有可無。比如我們上邊說張三給李四轉(zhuǎn)10元錢其實對應(yīng)MySQL中的兩條語句,我們就可以把這兩條語句放到一個事務(wù)中,完整的過程就是這樣:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE account SET balance = balance + 10 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

3.3 手動中止事務(wù)

如果我們寫了幾條語句之后發(fā)現(xiàn)上邊的某條語句寫錯了,我們可以手動的使用下邊這個語句來將數(shù)據(jù)庫恢復(fù)到事務(wù)執(zhí)行之前的樣子:ROLLBACK [WORK]

ROLLBACK語句就代表中止并回滾一個事務(wù),后邊的WORK可有可無類似的。比如我們在寫張三給李四轉(zhuǎn)賬10元錢對應(yīng)的MySQL語句時,先給張三扣了10元,然后一時大意只給李四賬戶上增加了1元,此時就可以使用ROLLBACK語句進行回滾,完整的過程就是這樣:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE account SET balance = balance + 1 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

這里需要強調(diào)一下,ROLLBACK語句是我們程序員手動的去回滾事務(wù)時才去使用的,如果事務(wù)在執(zhí)行過程中遇到了某些錯誤而無法繼續(xù)執(zhí)行的話,事務(wù)當身會當動的回滾。

小提示:
我們這里所說的開啟、提交、中止事務(wù)的語法只是針對使用?框框時通過mysql客戶端程序與服務(wù)器進行交互時控制事務(wù)的語法,如果大家使用的是別的客戶端程序,比如JDBC之類的,那需要參考相應(yīng)的文檔來看看如何控制事務(wù)。

3.4 支持事務(wù)的存儲引擎

MySQL中并不是所有存儲引擎都支持事務(wù)的功能,?前只有InnoDBNDB存儲引擎支持(,如果某個事務(wù)中包含了修改使用不支持事務(wù)的存儲引擎的表,那么對該使用不支持事務(wù)的存儲引擎的表所做的修改將無法進行回滾。比方說我們有兩個表,tbl1使用支持事務(wù)的存儲引擎InnoDBtbl2使用不支持事務(wù)的存儲引擎MyISAM,它們的建表語句如下所示:

mysql> CREATE TABLE demo14 (
    i int
) engine=InnoDB;
Query OK, 0 rows affected (0.05 sec)

mysql> CREATE TABLE demo15 (
    i int
) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)

我們看看先開啟一個事務(wù),寫一條插入語句后再回滾該事務(wù),demo14demo15的表現(xiàn)有什么不同:

mysql> SELECT * FROM demo14;
Empty set (0.00 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO demo14 VALUES(1);
Query OK, 1 row affected (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM demo14;
Empty set (0.00 sec)

以看到,對于使用支持事務(wù)的存儲引擎的demo14表來說,我們在插入一條記錄再回滾后,demo14就恢復(fù)到?jīng)]有插入記錄時的狀態(tài)了。再看看demo15表的表現(xiàn):

mysql> SELECT * FROM demo14;
Empty set (0.01 sec)

mysql> SELECT * FROM demo15;
Empty set (0.00 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO demo15 VALUES(1);
Query OK, 1 row affected (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SELECT * FROM demo15;
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.01 sec)

可以看到,雖然我們使用了ROLLBACK語句來回滾事務(wù),但是插入的那條記錄還是留在了demo15表中。

3.5 自動提交

MySQL中有一個系統(tǒng)變量autocommit

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set persist autocommit = 'ON';
Query OK, 0 rows affected (0.00 sec)

可以看到它的默認值為ON,也就是說默認情況下,如果我們不顯式的使用START TRANSACTION或者BEGIN語句開啟一個事務(wù),那么每一條語句都算是一個獨立的事務(wù),這種特性稱之為事務(wù)的當動提交。假如我們在張三向李四轉(zhuǎn)賬10元時不以START TRANSACTION或者BEGIN語句顯式的開啟一個事務(wù),那么下邊這兩條語句就相當于放到兩個獨立的事務(wù)中去執(zhí)行:

UPDATE account SET balance = balance - 10 WHERE id = 1;
UPDATE account SET balance = balance + 10 WHERE id = 2;

當然,如果我們想關(guān)閉這種當動提交的功能,可以使用下邊兩種方法之一:

  • 顯式的的使用START TRANSACTION或者BEGIN語句開啟一個事務(wù)。這樣在本次事務(wù)提交或者回滾前會暫時關(guān)閉掉當動提交的功能。
  • 把系統(tǒng)變量autocommit的值設(shè)置為OFF,就像這樣:SET autocommit = OFF;

這樣的話,我們寫入的多條語句就算是屬于同一個事務(wù)了,直到我們顯式的寫出COMMIT語句來把這個事務(wù)提交掉,或者顯式的寫出ROLLBACK語句來把這個事務(wù)回滾掉。

3.6 隱式提交

當我們使用START TRANSACTION或者BEGIN語句開啟了一個事務(wù),或者把系統(tǒng)變量autocommit的值設(shè)置為OFF時,事務(wù)就不會進行當動提交,但是如果我們輸入了某些語句之后就會悄悄的提交掉,就像我們輸入了COMMIT語句了一樣,這種因為某些特殊的語句而導(dǎo)致事務(wù)提交的情況稱為隱式提交,這些會導(dǎo)致事務(wù)隱式提交的語句包括:

  • 定義或修改數(shù)據(jù)庫對象的數(shù)據(jù)定義語言(Data definition language,縮寫為:DDL)。所謂的數(shù)據(jù)庫對象,指的就是數(shù)據(jù)庫、表、視圖、存儲過程等等這些東西。當我們使用CREATE、ALTERDROP等語句去修改這些所謂的數(shù)據(jù)庫對象時,就會隱式的提交前邊語句所屬于的事務(wù),就像這樣:

BEGIN;
SELECT ... #事務(wù)中的一條語句
UPDATE ... #事務(wù)中的一條語句
... #事務(wù)中的其它語句
CREATE TABLE ... # `此語句會隱式的提交前邊語句所屬于的事務(wù)

  • 隱式使用或修改mysql數(shù)據(jù)庫中的表

當我們使用ALTER USERCREATE USER、DROP USERGRANT、RENAME USER、REVOKE、SET PASSWORD等語句時也會隱式的提交前邊語句所屬于的事務(wù)。

  • 事務(wù)控制或關(guān)于鎖定的語句

當我們在一個事務(wù)還沒提交或者回滾時就又使用START TRANSACTION或者BEGIN語句開啟了另一個事務(wù)時,會隱式的提交上一個事務(wù),比如這樣:

BEGIN;
SELECT ... #事務(wù)中的一條語句
UPDATE ... #事務(wù)中的一條語句
... # 事務(wù)中的其它語句
BEGIN; # 此語句會隱式的提交前邊語句所屬于的事務(wù)

或者當前的autocommit系統(tǒng)變量的值為OFF,我們手動把它調(diào)為ON時,也會隱式的提交前邊語句所屬的事務(wù)。

或者使用`LOCK TABLES、UNLOCK TABLES等關(guān)于鎖定的語句也會隱式的提交前邊語句所屬的事務(wù)。

  • 加載數(shù)據(jù)的語句:比如我們使用LOAD DATA語句來批量往數(shù)據(jù)庫中導(dǎo)入數(shù)據(jù)時,也會隱式的提交前邊語句所屬的事務(wù)。
  • 關(guān)于MySQL復(fù)制的一些語句
    使用START SLAVE、STOP SLAVERESET SLAVE、CHANGE MASTER TO等語句時也會隱式的提交前邊語句所屬的事務(wù)。
  • 其它的一些語句

使用ANALYZE TABLE、CACHE INDEXCHECK TABLE、FLUSH、 LOAD INDEX INTO CACHEOPTIMIZE TABLE、REPAIR TABLERESET等語句也會隱式的提交前邊語句所屬的事務(wù)。

小提示:
上邊提到的一些語句,如果你都認識并且知道是干嘛用的那再好不過了,不認識也不要?餒,這里寫出來只是為了內(nèi)容的完整性,把可能會導(dǎo)致事務(wù)隱式提交的情況都列舉一下,具體每個語句都是干嘛用的等我們遇到了再說哈。

3.7 保存點

如果你開啟了一個事務(wù),并且已經(jīng)敲了很多語句,忽然發(fā)現(xiàn)上一條語句有點問題,你只好使用ROLLBACK語句來讓數(shù)據(jù)庫狀態(tài)恢復(fù)到事務(wù)執(zhí)行之前的樣子,然后一切從頭再來,總有一種一夜回到解放前的感覺。所以數(shù)據(jù)庫的提出了一個保存點(英文:savepoint)的概念,就是在事務(wù)對應(yīng)的數(shù)據(jù)庫語句中打幾個點,我們在調(diào)用ROLLBACK語句時可以指定會滾到哪個點,而不是回到最初的原點。定義保存點的語法如下:SAVEPOINT 保存點名稱

當我們想回滾到某個保存點時,可以使用下邊這個語句(下邊語句中的單詞WORKSAVEPOINT是可有可無的):ROLLBACK [WORK] TO [SAVEPOINT] 保存點名稱

不過如果ROLLBACK語句后邊不跟隨保存點名稱的話,會直接回滾到事務(wù)執(zhí)行之前的狀態(tài)。

如果我們想刪除某個保存點,可以使用這個語句:RELEASE SAVEPOINT 保存點名稱

下邊還是以張三向李四轉(zhuǎn)賬10元的例子展示一下保存點的用法,在執(zhí)行完扣除張三賬戶的錢10元的語句之后打一個保存點:

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 張三   |      12 |
|  2 | 李四   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SAVEPOINT s1;    # 一個保存點
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 張三   |       2 |
|  2 | 李四   |       2 |
+----+--------+---------+
2 rows in set (0.00 sec)

mysql> UPDATE account SET balance = balance + 1 WHERE id = 2; # 更新錯了
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> ROLLBACK TO s1;  # 回滾到保存點s1處
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM account;
+----+--------+---------+
| id | name   | balance |
+----+--------+---------+
|  1 | 張三   |       2 |
|  2 | 李四   |       2 |
+----+--------+---------+
2 rows in set (0.01 sec)

總結(jié)

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

相關(guān)文章

  • mysql5.6.19下子查詢?yōu)槭裁礋o法使用索引

    mysql5.6.19下子查詢?yōu)槭裁礋o法使用索引

    這篇文章主要介紹了mysql5.6.19下子查詢?yōu)槭裁礋o法使用索引,需要的朋友可以參考下
    2014-08-08
  • 淺析MySQL如何實現(xiàn)事務(wù)隔離

    淺析MySQL如何實現(xiàn)事務(wù)隔離

    使用過關(guān)系型數(shù)據(jù)庫的,應(yīng)該都事務(wù)的概念有所了解,知道事務(wù)有 ACID 四個基本屬性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability),今天我們主要來理解一下事務(wù)的隔離性
    2021-06-06
  • MySQL刪除數(shù)據(jù)后自增主鍵ID不連貫問題及解決

    MySQL刪除數(shù)據(jù)后自增主鍵ID不連貫問題及解決

    這篇文章主要介紹了MySQL刪除數(shù)據(jù)后自增主鍵ID不連貫問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • mysql時間戳格式化函數(shù)from_unixtime使用的簡單說明

    mysql時間戳格式化函數(shù)from_unixtime使用的簡單說明

    mysql中的FROM_UNIXTIME函數(shù)可以數(shù)據(jù)庫中整型類的時間戳格式化為字符串的日期時間格式,下面這篇文章主要給大家介紹了關(guān)于mysql時間戳格式化函數(shù)from_unixtime使用的簡單說明,需要的朋友可以參考下
    2022-08-08
  • mysql函數(shù)日期和時間函數(shù)匯總

    mysql函數(shù)日期和時間函數(shù)匯總

    這篇文章主要介紹了mysql函數(shù)日期和時間函數(shù)匯總,日期和時間函數(shù)主要用來處理日期和時間值,一般的日期函數(shù)除了使用??date???類型的參數(shù)外,也可以使用??datetime???或者??timestamp??類型的參數(shù),但會忽略這些值的時間部分
    2022-07-07
  • CentOS7環(huán)境下安裝MySQL5.5數(shù)據(jù)庫

    CentOS7環(huán)境下安裝MySQL5.5數(shù)據(jù)庫

    大家好,本篇文章主要講的是CentOS7環(huán)境下安裝MySQL5.5數(shù)據(jù)庫,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • mysql5.6安裝配置方法圖文教程

    mysql5.6安裝配置方法圖文教程

    這篇文章主要為大家分享了mysql5.6安裝配置方法圖文教程,感興趣的朋友可以參考一下
    2016-06-06
  • MySQL如何添加外鍵

    MySQL如何添加外鍵

    MySQL是一種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),它支持外鍵的添加,本文主要介紹了MySQL如何添加外鍵,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • MySQL多版本并發(fā)控制mvcc原理淺析

    MySQL多版本并發(fā)控制mvcc原理淺析

    mvcc多版本并發(fā)控制是一種數(shù)據(jù)庫的并發(fā)控制機制,本文主要介紹了MySQL多版本并發(fā)控制mvcc原理淺析,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • mysql cmd常用命令

    mysql cmd常用命令

    mysql cmd常用命令,偶爾需要命令行執(zhí)行mysql的朋友可以參考下。
    2011-05-05

最新評論