1、LOCK TABLE 和 UNLOCK TABLEmysql
lock tables 鎖定當前線性表。若是表被其餘線程鎖定,則當前線程會等待,直到能夠獲取全部鎖定爲止。sql
unlock tables 釋放當前線程得到的任何鎖定。當前線程執行另外一個 LOCK TABLES 時, 或當與服務器的鏈接被關閉時,全部由當前線程鎖定的表被隱含地解鎖 數據庫
一個得到表鎖和釋放表鎖的簡單例子服務器
session_1 | session_2 |
得到表film_text的Read鎖定session lock table film_text read分佈式 |
|
當前session能夠查詢該表紀錄spa select id,title from film_text where id = 1;線程 +-------+-----------orm id. title事務 +--------+---------- 1 標籤 |
其餘session也能夠查詢該表的紀錄 select id,title from film_text where id = 1; +-------+----------- id. title +--------+---------- 1 標籤
|
其餘session更新鎖定表會等待得到鎖 update film_text set title='lalamei' where id=1; ......等待 |
|
釋放鎖:unlock tables | ......等待 |
session 得到鎖,更新操做完成 完成 |
2、事務控制
默認狀況下,MySQL 是自動提交(Autocommit)的,若是須要經過明確的 Commit 和 Rollback 來提交和回滾事務,那麼須要經過明確的事務控制命令來開始事務 。
* start transaction 或 begin語句能夠開始一項新的事務
* commit 和 rollback 用來提交或者回滾事務
* chain 和 release 字句分別用來定義在事務提交或者回滾以後的操做,chain會當即啓動一個新事物,而且和剛纔的事物具備相同的隔離級別,release則會斷開和客戶端鏈接
* set autocommit 能夠修改當前鏈接的提交方式,若是設置了set autocommit=0,則設置以後的全部事務都須要經過明確的命令進行提交或者回滾
演示使用start transaction 開始的事務在提交後自動回到自動提交的方式;若是在提交的時候使用commit and chain,那麼會在提交後當即開啓一個新的事務。
start transaction和commit and chain 的使用例子
session_1 | session_2 |
從表actor中查詢actor_id=201的記錄,結果爲空: mysql> select * from actor where actor_id = 201; Empty set (0.00 sec) |
從表actor中查詢actor_id=201的記錄,結果爲空: mysql> select * from actor where actor_id = 201; Empty set (0.00 sec) |
用start transaction 命令啓動一個事務,往表actor中插入一條紀錄,沒有commit: mysql> start transaction; Query OK, 0 rows affected (0.00 sec)
mysql> insert into actor(actor_id,first_name,last_name) values(201,'lisa','tom'); Query OK, 1 row affected (0.00 sec) |
查詢表actor,結果仍然爲空: mysql> select * from actor where actor_id=201; Empty set (0.00 sec)
|
執行提交: mysql> commit; Query OK, 0 rows affected (0.00 sec) |
|
再次查詢表actor,能夠查詢到結果: mysql> select * from actor where actor_id=201; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 201 | lisa | tom | +----------+------------+-----------+ 1 row in set (0.00 sec) |
|
這個事務是按照自動提交執行的: mysql> insert into actor(actor_id,first_name,last_name) values(202,'lisa','lan'); Query OK, 1 row affected (0.01 sec) |
|
能夠從actor表中查詢到session1剛剛插入的數據。 mysql> select * from actor where actor_id in (201,202); +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 201 | lisa | tom | | 202 | lisa | lan | +----------+------------+-----------+ 2 rows in set (0.00 sec) |
|
從新用start transaction 啓動一個事務: mysql> start transaction; Query OK, 0 rows affected (0.00 sec)
往表actor中插入一條紀錄: mysql> insert into actor(actor_id,first_name,last_name) values(203,'lisa','tt'); Query OK, 1 row affected (0.00 sec)
用commit and chain命令提交: mysql> commit and chain; Query OK, 0 rows affected (0.00 sec)
此時自動開始一個新的事務: mysql> insert into actor (actor_id,first_name,last_name) values(204,'Lisa','Mou'); Query OK, 1 row affected (0.00 sec) |
|
session1剛插入的紀錄沒法查看: mysql> select * from actor where first_name = 'lisa'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 201 | lisa | tom | | 202 | lisa | lan | | 203 | lisa | tt | +----------+------------+-----------+ 3 rows in set (0.00 sec) |
|
用commit命令提交: mysql> commit; Query OK, 0 rows affected (0.01 sec) |
|
session1插入的新記錄能夠看到: mysql> select * from actor where first_name = 'lisa'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 201 | lisa | tom | | 202 | lisa | lan | | 203 | lisa | tt | | 204 | lisa | mou | +----------+------------+-----------+ 4 rows in set (0.00 sec) |
若是在鎖表期間,用 start sransaction 命令開始一個新事務,會形成一個隱含的unlock tables 被執行
start transaction 致使的 unlock tables
session_1 | session_2 |
從表actor中查詢actor_id=301的記錄,結果爲空: mysql> select * from actor where actor_id = 301; Empty set (0.00 sec) |
從表actor中查詢actor_id=301的記錄,結果爲空: mysql> select * from actor where actor_id = 301; Empty set (0.00 sec) |
對錶actor加寫鎖: mysql> lock table actor write; Query OK, 0 rows affected (0.00 sec) |
|
對錶 actor 的讀寫操做被阻塞: mysql> select * from actor where actor_id=301; ....等待 |
|
插入一條記錄 mysql> insert into actor(actor_id,first_name,last_name) values(301,'Lisa','Tom'); Query OK, 1 row affected (0.00 sec) |
....等待 |
回滾剛纔的紀錄: mysql> rollback; Query OK, 0 rows affected (0.00 sec) |
....等待 |
用start transaction 命令從新開始一個事務: mysql> start transaction; Query OK, 0 rows affected (0.00 sec) |
....等待 |
session1 開始一個事務時,表鎖被釋放,能夠查詢: mysql> select * from actor where actor_id=301; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 301 | Lisa | Tom | +----------+------------+-----------+ 1 row in set (14 min 58.07 sec) 對lock方式加的表鎖,不能經過rollback進行回滾。 |
/*
* 一、commit、rollback只能對事務類型的表進行提交和回滾
* 二、一般對提交的事務紀錄到二進制文件中
* 三、全部的DDL語句是不能回滾的,部分DDL語句會形成隱式提交
*/
在事務中能夠經過定義 SAVEPOINT,指定回滾事務的一個部分,可是不能指定提交事務 的一個部分。對於複雜的應用,能夠定義多個不一樣的 SAVEPOINT,知足不一樣的條件時,回滾 不一樣的 SAVEPOINT。須要注意的是,若是定義了相同名字的 SAVEPOINT,則後面定義的 SAVEPOINT 會覆蓋以前的定義。對於再也不須要使用的 SAVEPOINT,能夠經過 RELEASE SAVEPOINT 命令刪除 SAVEPOINT,刪除後的 SAVEPOINT,不能再執行 ROLLBACK TO SAVEPOINT 命令。
模擬回滾事務
session_1 | session_2 |
從表actor中查詢 first_name='Simon' 的紀錄, 結果爲空: mysql> select * from actor where first_name = 'Simon'; Empty set (0.00 sec) |
從表actor中查詢 first_name='Simon' 的紀錄, 結果爲空: mysql> select * from actor where first_name = 'Simon'; Empty set (0.00 sec) |
啓動一個事務,往表 actor 中插入一條紀錄; mysql> start transaction; Query OK, 0 rows affected (0.00 sec)
mysql> insert into actor(actor_id,first_name,last_name) values(501,'Simon','Tom'); Query OK, 1 row affected (0.00 sec) |
|
能夠查詢到剛剛插入的紀錄: mysql> select * from actor where first_name = 'Simon'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 501 | Simon | Tom | +----------+------------+-----------+ 1 row in set (0.00 sec)
|
沒法從actor表中查詢到session1剛插入的紀錄: mysql> select * from actor where first_name = 'Simon'; Empty set (0.00 sec)
|
定義 savepoint,名稱爲test; mysql> savepoint test; Query OK, 0 rows affected (0.00 sec)
繼續插入一條紀錄: mysql> insert into actor(actor_id,first_name,last_name) values(502,'Simon','Cof'); Query OK, 1 row affected (0.00 sec) |
|
能夠查詢到兩條紀錄 mysql> select * from actor where first_name = 'Simon'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 501 | Simon | Tom | | 502 | Simon | Cof | +----------+------------+-----------+ 2 rows in set (0.00 sec) |
仍然沒法查詢到結果: mysql> select * from actor where first_name = 'Simon'; Empty set (0.00 sec)
|
回滾到剛纔定義的savepoint: mysql> rollback to savepoint test; Query OK, 0 rows affected (0.00 sec) |
|
只能從表 actor 中查詢到第一條記錄,由於第二條記錄已經回滾: mysql> select * from actor where first_name = 'Simon'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 501 | Simon | Tom | +----------+------------+-----------+ 1 row in set (0.00 sec) |
仍然沒法查詢到結果: mysql> select * from actor where first_name = 'Simon'; Empty set (0.00 sec) |
用commit命令提交: mysql> commit; Query OK, 0 rows affected (0.00 sec) |
|
只能從表 actor 中查詢到第一條記錄: mysql> select * from actor where first_name = 'Simon'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 501 | Simon | Tom | +----------+------------+-----------+ 1 row in set (0.00 sec) |
只能從表 actor 中查詢到 session1 插入的第一條記錄: mysql> select * from actor where first_name = 'Simon'; +----------+------------+-----------+ | actor_id | first_name | last_name | +----------+------------+-----------+ | 501 | Simon | Tom | +----------+------------+-----------+ 1 row in set (0.00 sec) |
3、分佈式事務的使用
簡介
一、分佈式事務只支持innoDB存儲引擎
二、一個分佈式事務會涉及多個行動,這些行動自己是事務性的。全部行動都必須一塊兒成功完成,或者一塊兒被回滾
分佈式事務的原理
分佈式事務語法
XA {START|BEGIN} xid [JOIN|RESUMF]
XA START xid 用於啓動一個帶給xid值的XA事務。每一個XA事務必須有一個惟一的xid值,所以該值當前不能被其餘的XA事務使用。
xid是一個XA事務標識符,用來惟一標識一個分佈式事務。xid值由客服端提供,或由mysql服務器生成。
xid值包含1~3個部分
xid : gtrid [, bqual [, formatId ] ]
* gtrid 是一個分佈式事務標識符,相同的分佈式事務應該使用相同的gtrid,這樣能夠明確知道xa事務屬於那個分佈式事務。
* bqual 是一個分支限定符,默認值是空串。對於一個分佈式事務中的每一個分支事務,bqual值必須是惟一的。
* formatID 是一個數字,用於標識由gtrid 和 bqual 值使用的格式,默認值是1。
下面其餘 XA 語法中用到的 xid 值,都必須和 START 操做使用的 xid 值相同,也就是表示 對這個啓動的 XA 事務進行操做。
XA PREPARE xid
使事務進入 PREPARE 狀態,也就是兩階段提交的第一個提交階段
這兩個命令用來提交或者回滾具體的分支事務。也就是兩階段提交的第二個提交階段, 分支事務被實際的提交或者回滾。
XA RECOVER
XA RECOVER返回當前數據庫中處於PREPARE 狀態的分支事務的詳細信息。
分佈式的關鍵在於?
如何確保分佈式事務的完整性,
在某個分支出現問題時的故障解決。
演示了一個簡單的分佈式事務的執行,事務的內容是在 DB1 中插入一條記錄, 同時在 DB2 中更新一條記錄,兩個操做做爲同一事務提交或者回滾。
分佈式事務例子
session_1 in DB1 | session_2 in DB2 |
在數據庫 DB1 中啓動一個分佈式事務的一個分支事務,xid 的 gtrid 爲test,bqual 爲 db1: mysql> xa start 'test','db1'; Query OK, 0 rows affected (0.00 sec)
分支事務1在表 actor 中插入一條紀錄: mysql> insert into actor(actor_id,first_name,last_name) values(601,'Simon','Tom'); Query OK, 1 row affected (0.00 sec)
對分支事務1進行第一階段提交,進入 prepare 狀態: mysql> xa end 'test','db1'; Query OK, 0 rows affected (0.00 sec)
mysql> xa prepare 'test','db1'; Query OK, 0 rows affected (0.00 sec) |
在數據庫DB2中啓動分佈式事務test的另外一個分支事務,xid 的 gtrid 爲 test, bqual 爲 db2: mysql> xa start 'test','db2'; Query OK, 0 rows affected (0.00 sec)
分支事務 2 在表 film_actor 中更新了21條記錄: mysql> update film_actor set last_update=now() where actor_id=178; Query OK, 21 rows affected (0.00 sec) Rows matched: 21 Changed: 21 Warnings: 0
對分支事務 2 進行第一階段提交,進入 prepare 狀態: mysql> xa end 'test','db2'; Query OK, 0 rows affected (0.00 sec)
mysql> xa prepare 'test','db2'; Query OK, 0 rows affected (0.01 sec) |
用 xa recover 命令查看當前分支事務狀態: mysql> xa recover \G; *************************** *************************** formatID: 1 gtrid_length: 4 bqual_length: 3 data: testdb1 1 rows in set (0.00 sec) |
用 xa recover 命令查看當前分支事務狀態: mysql> xa recover \G; *************************** *************************** formatID: 1 gtrid_length: 4 bqual_length: 3 data: testdb2 1 rows in set (0.00 sec) |
兩個事務都進入準備提交階段,若是以前遇到任何錯誤,都應該回滾全部的分支,以確保分佈事務的正確。 | |
提交分支事務 1: mysql> xa commit 'test','db1'; Query OK, 0 rows affected (0.00 sec) |
提交分支事務2: mysql> xa commit 'test','db2'; Query OK, 0 rows affected (0.00 sec)
|
兩個事務都到達準備提交階段後,一旦開始進行提交操做,就須要確保所有的分支都提交成功。 |
存在的問題1
條件:
分支事務在達到prepare狀態時,數據庫異常從新啓動,重啓之後能夠繼續執行事務進行提交回滾的操做。
問題:
提交事務沒有寫binlog,存在隱患,可能致使使用binlog恢復丟失部分數據。若是存在複製的數據庫,則有可能致使主從數據庫的數據不一致。
存在問題二
若是分支事務的客戶端鏈接異常停止,那麼數據庫會自動回滾未完成的分支事務,若是 此時分支事務已經執行到 prepare 狀態,那麼這個分佈式事務的其餘分支可能已經成功提交, 若是這個分支回滾,可能致使分佈式事務的不完整,丟失部分分支事務的內容。