【MySQL 06】事務處理

黄舟
發布: 2017-02-04 11:57:04
原創
1215 人瀏覽過

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 |
+------------+------------+------------+--------------+
登入後複製

(2) SET AUTOCOMMIT=0:INT

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)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!