【MySQL 06】事務處理

1、事務的ACID性質

事務具有4個特性:原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持續性(durablility)。

以“銀行轉帳”為例:

  • 原子性(Atomicity):組成事務處理的語句形成了一個邏輯單元,不能只執行其中的一部分。換句話說,事務是不可分割的最小單元。比如:銀行轉帳過程中,必須同時從一個帳戶減去轉帳金額,并加到另一個帳戶中,只改變一個帳戶是不合理的。

  • 一致性(Consistency): 在事務處理執行前后,數據庫是一致的。也就是說,事務應該正確的轉換系統狀態。比如:銀行轉帳過程中,要么轉帳金額從一個帳戶轉入另一個帳戶,要么兩個帳戶都不變,沒有其他的情況。

  • 隔離性(Isolation) :一個事務處理對另一個事務處理沒有影響。就是說任何事務都不可能看到一個處在不完整狀態下的事務。比如說,銀行轉帳過程中,在轉帳事務沒有提交之前,另一個轉帳事務只能處于等待狀態。

  • 持續性(Durablility):事務處理的效果能夠被永久保存下來。反過來說,事務應當能夠承受所有的失敗,包括服務器、進程、通信以及媒體失敗等等。比如:銀行轉帳過程中,轉帳后帳戶的狀態要能被保存下來。

2、事務狀態

SET?AUTOCOMMIT?=?0?,?禁止自動提交?SET?AUTOCOMMIT?=?1,?開啟自動提交  START?TRANSACTION:開始事務,autocommit設為0,如果已經有一個事務在運行,則會觸發一個隱藏的COMMIT  COMMIT:提交事務,保存更改,釋放鎖  ROLLBACK:回滾本事務對數據庫的所有更改,然后結束事務,釋放鎖  SAVEPOINT?savepoint_name:創建一個savepoint識別符來ROLLBACK?TO?SAVEPOINT  ROLLBACK?TO?SAVEPOINT?savepoint_name:回滾到從savepoint_name開始對數據庫的所有更改,這樣就允許回滾事務中的一部分,保證更改的一個子集被提交  SET?TRANSACTION:允許設置事務的隔離級別  LOCK?TABLES:允許顯式的鎖住一個或多個table,會隱式的關閉當前打開的事務,建議在執行LOCK?TABLES語句之前顯式的commit或rollback。  我們一般所以一般在事務代碼里不會使用LOCK?TABLES

3、事務操作

(1) 首先創建employee數據表:

mysql>?create?table?employee(  ????->?employeeID?char(4),  ????->?name?varchar(20)?not?null,  ????->?job?varchar(20),  ????->?departmentID?int  ????->?);  Query?OK,?0?rows?affected?(0.10?sec)    mysql>?insert?into?employee?value?('7513'?,?'Nora?Edwar'?,?'Programmer',?128);  mysql>?insert?into?employee?value?('9006'?,?'Candy?Burn'?,?'Systems?Ad',128?);  mysql>?insert?into?employee?value?(?'9842'?,?'Ben?Smith'?,??'DBA'?,?42);  mysql>?insert?into?employee?value?('9843',??'Pert?Park'??,?'DBA'?,?42?);  mysql>?insert?into?employee?value?('9845'?,?'Ben?Patel'??,?'DBA'?,?128?);  mysql>?insert?into?employee?value?('9846'?,?'Red?Right'?,??null,?128?);  mysql>?insert?into?employee?value?('9847'?,?'Run?Wild'??,??null?,?128?);  mysql>?insert?into?employee?value?('9848'?,?'Rip?This?J'?,?null?,?128?);  mysql>?insert?into?employee?value?('9849'?,?'Rip?This?J'?,?null??,?128?);  mysql>?insert?into?employee?value?(?'9850'?,?'Reader?U'?,???null?,?128?);  mysql>?insert?into?employee?value?('6651',??'Ajay?Patel'?,?'Programmer',?128?);    mysql>?select?*?from?employee;  +------------+------------+------------+--------------+  |?employeeID?|?name???????|?job????????|?departmentID?|  +------------+------------+------------+--------------+  |?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?7513???????|?Nora?Edwar?|?Programmer?|??????????128?|  |?9006???????|?Candy?Burn?|?Systems?Ad?|??????????128?|  |?9842???????|?Ben?Smith??|?DBA????????|???????????42?|  |?9843???????|?Pert?Park??|?DBA????????|???????????42?|  |?9845???????|?Ben?Patel??|?DBA????????|??????????128?|  |?9846???????|?Red?Right??|?NULL???????|??????????128?|  |?9847???????|?Run?Wild???|?NULL???????|??????????128?|  |?9848???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9849???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9850???????|?Reader?U???|?NULL???????|??????????128?|  |?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  +------------+------------+------------+--------------+

(2) SET AUTOCOMMIT=0:

mysql>?set?autocommit?=?0;//禁止自動提交    mysql>?insert?into?employee?values(null,'test1',null,128);    mysql>?savepoint?s1;//創建一個savepoint識別符    mysql>?insert?into?employee?values(null,"test2",null,128);    mysql>?savepoint?s2;//創建一個savepoint識別符    mysql>?insert?into?employee?values(null,"test3",null,128);    mysql>?savepoint?s3;//創建一個savepoint識別符mysql>?select?*?from?employee;  +------------+------------+------------+--------------+|?employeeID?|?name???????|?job????????|?departmentID?|  +------------+------------+------------+--------------+|?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?7513???????|?Nora?Edwar?|?Programmer?|??????????128?|  |?9006???????|?Candy?Burn?|?Systems?Ad?|??????????128?|  |?9842???????|?Ben?Smith??|?DBA????????|???????????42?|  |?9843???????|?Pert?Park??|?DBA????????|???????????42?|  |?9845???????|?Ben?Patel??|?DBA????????|??????????128?|  |?9846???????|?Red?Right??|?NULL???????|??????????128?|  |?9847???????|?Run?Wild???|?NULL???????|??????????128?|  |?9848???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9849???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9850???????|?Reader?U???|?NULL???????|??????????128?|  |?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?NULL???????|?test1??????|?NULL???????|??????????128?|  |?NULL???????|?test2??????|?NULL???????|??????????128?||?NULL???????|?test3??????|?NULL????|????128?|  +------------+------------+------------+--------------+

(3) ROLLBACK TO SAVEPOINT:

mysql>?rollback?to?savepoint?s1;//回滾到s1標簽處:mysql>?select?*?from?employee;  +------------+------------+------------+--------------+|?employeeID?|?name???????|?job????????|?departmentID?|  +------------+------------+------------+--------------+|?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?7513???????|?Nora?Edwar?|?Programmer?|??????????128?|  |?9006???????|?Candy?Burn?|?Systems?Ad?|??????????128?|  |?9842???????|?Ben?Smith??|?DBA????????|???????????42?|  |?9843???????|?Pert?Park??|?DBA????????|???????????42?|  |?9845???????|?Ben?Patel??|?DBA????????|??????????128?|  |?9846???????|?Red?Right??|?NULL???????|??????????128?|  |?9847???????|?Run?Wild???|?NULL???????|??????????128?|  |?9848???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9849???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9850???????|?Reader?U???|?NULL???????|??????????128?|  |?6651???????|?Ajay?Patel?|?Programmer?|??????????128?||?NULL???????|?test1??????|?NULL???????|??????128?|  +------------+------------+------------+--------------+

(4) COMMIT:

mysql>?commit;//提交事務  mysql>?rollback?to?savepoint?s2;  //一旦事務提交了,就不能再回滾ERROR?1305?(42000):?SAVEPOINT?s2?does?not?exist

(5) SET AUTOCOMMIT=1:

mysql>?set?autocommit?=?1;//自動提交事務    mysql>??insert?into?employee?values(null,"test4",null,128);    mysql>?savepoint?s4;//一旦創建,自動提交mysql>?select?*?from?employee;  +------------+------------+------------+--------------+|?employeeID?|?name???????|?job????????|?departmentID?|  +------------+------------+------------+--------------+|?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?7513???????|?Nora?Edwar?|?Programmer?|??????????128?|  |?9006???????|?Candy?Burn?|?Systems?Ad?|??????????128?|  |?9842???????|?Ben?Smith??|?DBA????????|???????????42?|  |?9843???????|?Pert?Park??|?DBA????????|???????????42?|  |?9845???????|?Ben?Patel??|?DBA????????|??????????128?|  |?9846???????|?Red?Right??|?NULL???????|??????????128?|  |?9847???????|?Run?Wild???|?NULL???????|??????????128?|  |?9848???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9849???????|?Rip?This?J?|?NULL???????|??????????128?|  |?9850???????|?Reader?U???|?NULL???????|??????????128?|  |?6651???????|?Ajay?Patel?|?Programmer?|??????????128?|  |?NULL???????|?test1??????|?NULL???????|??????????128?|  |?NULL???????|?test2??????|?NULL???????|??????????128?|  |?NULL???????|?test3??????|?NULL???????|??????????128?||?NULL???????|?test4??????|?NULL???????|??????????128?|  +------------+------------+------------+--------------+mysql>?rollback?to?s4;//此時就無法回滾了  ERROR?1305?(42000):?SAVEPOINT?s4?does?not?exist

4、鎖

共享鎖、排它鎖、悲觀鎖、樂觀鎖、行級鎖、表級鎖

  • 共享鎖: 就是在讀取數據的時候,給數據添加一個共享鎖。共享和共享直接是不沖突的,但是和排他鎖是沖突的。

  • 排他鎖: 更新數據的時候,安裝排他鎖,禁止其他一切行為。

  • 悲觀鎖:更新多,查詢少時用,悲觀鎖不是數據庫中真正的鎖,是人們看待事務的態度。

  • 樂觀鎖:更新少,查詢多時用,樂觀鎖也不是數據庫中真正的鎖,是人們看待事務的態度。

5、并發處理

  • 臟讀:一個事務讀取到了另外一個事務沒有提交的數據?
    事務1:更新一條數據?
    ———>事務2:讀取事務1更新的記錄?
    事務1:調用commit進行提交?
    此時事務2讀取到的數據是保存在數據庫內存中的數據,稱為臟讀。?
    讀到的數據為臟數據?
    詳細解釋:?
    臟讀就是指:當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,?
    另外一個事務也訪問這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據,那么另外一個?
    事務讀到的這個數據是臟數據,依據臟數據所做的操作可能是不正確的。

  • 不可重復讀:在同一事務中,兩次讀取同一數據,得到內容不同?
    事務1:查詢一條記錄?
    ———->事務2:更新事務1查詢的記錄?
    ———->事務2:調用commit進行提交?
    事務1:再次查詢上次的記錄?
    此時事務1對同一數據查詢了兩次,可得到的內容不同,稱為不可重復讀

  • 幻讀:同一事務中,用同樣的操作讀取兩次,得到的記錄數不相同?
    事務1:查詢表中所有記錄?
    ———->事務2:插入一條記錄?
    ———->事務2:調用commit進行提交?
    事務1:再次查詢表中所有記錄?
    此時事務1兩次查詢到的記錄是不一樣的,稱為幻讀?
    詳細解釋:?
    幻讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,?
    這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表?
    中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,?
    就好象發生了幻覺一樣。

6、事務隔離

事務隔離五種級別:

TRANSACTION_NONE?不使用事務。?  TRANSACTION_READ_UNCOMMITTED?允許臟讀。?  TRANSACTION_READ_COMMITTED?防止臟讀,最常用的隔離級別,并且是大多數數據庫的默認隔離級別?  TRANSACTION_REPEATABLE_READ?可以防止臟讀和不可重復讀,?  TRANSACTION_SERIALIZABLE?可以防止臟讀,不可重復讀取和幻讀,(事務串行化)會降低數據庫的效率

以上的五個事務隔離級別都是在Connection接口中定義的靜態常量,

使用setTransactionIsolation(int level) 方法可以設置事務隔離級別。?
如:con.setTransactionIsolation(Connection.REPEATABLE_READ);

注意:事務的隔離級別受到數據庫的限制,不同的數據庫支持的的隔離級別不一定相同

summary:?  (1)Serializable:可避免臟讀、不可重復讀、虛讀情況的發生。?  (2)Repeatable?read:可避免臟讀、不可重復讀情況的發生。(可重復讀,是?MySQL?默認的事務隔離級別)?  (3)Read?committed:可避免臟讀情況發生。(讀取已提交的數據)?  (4)Read?uncommitted:最低級別,以上情況均無法保證。(讀取到了未提交的數據)

以上就是?【MySQL 06】事務處理的內容,更多相關內容請關注PHP中文網(www.php.cn)!

? 版權聲明
THE END
喜歡就支持一下吧
點贊15 分享