事務簡介
事務是一組操作的集合,它是一個不可分割的工作單位,事務會把所有的操作作為一個整體一起向系統提交或或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。
典型事例:銀行轉賬操作
假設張三向李四進行轉賬操作首先第一步我們應該查詢張三用戶的余額,如果余額充足,則張三用戶余額減少,最后李四用戶余額增加
事務的步驟分為:1、開啟事務2、回滾事務(把臨時修改的數據恢復回去,能夠保證如果出現異常,全部操作都會回滾,保證數據的完整性和一致性)3、提交事務
默認MySQL的事務是自動提交的,也就是說,當執行一條DML語句,MySQL會立即隱式的提交事務。
事務操作?
· 查看/設置事務提交方式
SELECT @@autocommit;
SET @@autocommit=0;
· 提交事務
COMMIT;?
· 回滾事務
ROLLBACK;?
#事務操作
#數據準備
create table account(id int primary key auto_increment comment '主鍵ID',name varchar(10) comment '姓名',money int comment '余額'
)comment '賬戶表';
insert into account values(null,'張三',2000),(null,'李四',2000);
#轉賬操作
select @@autocommit;
set @@autocommit=0;
select * from account where name='張三';
#2、將張三賬戶余額減1000
update account set money =money-1000 where name='張三';
程序執行錯誤
#3、將李四賬戶余額增加1000
update account set money =money+1000 where name='李四';
#提交事務
commit;
#回滾事務
rollback;
#恢復數據
update account set money=2000 where name='張三'||name='李四';
方式二:不設置事務的提交方式
·? 開啟事務
START TRANSACTION 或 BEGIN;
·? 提交事務
COMMIT;?
?·? 回滾事務
rollback;
#方式二:
start transaction ;
set @@autocommit=1;
select * from account where name='張三';
#2、將張三賬戶余額減1000
update account set money =money-1000 where name='張三';
程序執行錯誤...
#3、將李四賬戶余額增加1000
update account set money =money+1000 where name='李四';
#提交事務
commit;
#回滾事務
rollback;
事務四大特性:ACID
?· 原子性(Atomicity):事務是不可分割的最小操作單元,要么全部成功,要么全部失敗。
· 一致性(Consistency):事務完成時,必須使所有的數據都保持一致狀態。
· 隔離性(Isolation):數據庫系統提供的隔離機制,保證事務在不受外部并發操作影響的獨立環境下運行。
· 持久性(Durability):事務一旦提交或回滾,它對數據庫中的數據的改變就是永久的。
并發事務問題?
問題 | 描述 |
臟讀 | 一個事務讀到另一個事務還沒有提交的數據 |
不可重復讀 | 一個事務先后讀取同一條記錄,但兩次讀取的數據不同,稱之為不可重復讀 |
幻讀 | 一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入數據時,又發現這行數據已經存在,好像出現了”幻影“ |
?
?
事務的隔離級別?
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable Read(默認) | × | × | √ |
Serializable | × | × | × |
注意:從上到下隔離級別越來越高,?Serializable隔離級別最高但性能最差;Read uncommitted隔離級別最低(數據安全性最差),但性能最優。
#查詢事務隔離級別
SELECT @@TRANSACTION_ISOLATION;
#設置事務隔離級別
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
#查看事物的隔離級別
select @@transaction_isolation;
#設置事務隔離級別
set session transaction isolation level read uncommitted;
#改回默認值
set session transaction isolation level repeatable read ;
臟讀演示:(兩個客戶端演示)
#第一個客戶端
mysql> use test
Database changed
mysql> set session transaction isolation level read uncommitted-> ;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 2000 |
| 2 | 李四 | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 2000 |
| 2 | 李四 | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 1000 |
| 2 | 李四 | 2000 |
+----+------+-------+
#第二個客戶端
mysql> use test
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> update account set money=money-1000 where name='張三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
不可重復讀:(此時隔離級別為Read committed)
#第一個客戶端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 1000 |
| 2 | 李四 | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 2000 |
| 2 | 李四 | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)
#第二個客戶端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> update account set money=money+1000 where name='張三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> commit;
Query OK, 0 rows affected (0.00 sec)
幻讀:(此時隔離級別為Repeatable read)
#第一個客戶端start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 2000 |
| 2 | 李四 | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)mysql> select * from account where id=3;
Empty set (0.00 sec)insert into account(id,name,money) values(3,'王小五',2000);
ERROR 1062 (23000): Duplicate entry '3' for key 'account.PRIMARY'
mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | 張三 | 2000 |
| 2 | 李四 | 2000 |
| 3 | 王五 | 2000 |
+----+------+-------+
3 rows in set (0.00 sec)
#第二個客戶端start transaction;
Query OK, 0 rows affected (0.00 sec)mysql> insert into account(id,name,money) values(3,'王五',2000);
Query OK, 1 row affected (0.00 sec)mysql> commit;
Query OK, 0 rows affected (0.00 sec)
?
?
?
?
?
?