文章目录
概念:mysql中,事务是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性。
以银行转账为例:
-- A支出100,B收款100
update user set money = money-100 where name = 'A';
update user set money = money+100 where name = 'B';
如果执行过程中只有一条执行成功,另一条失败,那么系统数据就会出现错误。
所以在开发过程中,有时就要求多条sql语句,同时成功或者失败(不可分割),这是事务要做的事情。
mysql中如何控制事务?
1. autocommit 自动提交
- mysql 默认是开启的
select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.01 sec)
-- 自动提交:但我们去执行一个sql语句的时候,效果会立即提现,且不会回滚
-- 事务回滚值的是撤销sql语句执行效果,
rollback;
-- 即执行之后,即使执行rollback;语句,也不会这小执行效果。
-- 要想取消操作,要设置autocommit = 0,关闭自动提交;
set autocommit = 0;
insert into user values(2,'b',100);
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 2 | b | 100 |
+----+------+-------+
-- 再回滚,那么可以撤销执行
rollback;
select * from user;
Empty set (0.00 sec)
-- 再次插入数据,并手动提交,再回滚也不能撤销
insert into user values(2,'b',100);
commit;
rollback;
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 2 | b | 100 |
+----+------+-------+
1 row in set (0.00 sec)
以上例子说明自动提交能防止事务回滚,从一方面说明,一旦提交(自动或者手动),那么都 无法回滚(持久性)。
综上所述,事务包括:
- 自动提交 : @@autocommit=1;
- 手动提交:commit;
- 事务回滚:rollback;
事务给我们提供了一个反悔的机会
回过头来看转账,通过取消自动取消,在进行rollback可以取消操作
update user set money = money-100 where name = 'A';
update user set money = money+100 where name = 'B';
rollback;
2. 使用begin 或者 start transaction来手动开启一个事务
begin;
update user set money = money-100 where name = 'A';
update user set money = money+100 where name = 'B';
rollback;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 1000 |
| 2 | b | 1000 |
+----+------+-------+
-- 把begin换成transaction可以达到同样的效果。
-- 一旦commit, 那么事务已经结束,rollback也没用
总结:事务四大特征ACID
- A(atomic)原子性:事务是最小的单位,不可以分割
- C(consistency)一致性:同一事务中的sql语句要同时成功或者同时失败
- I(isolation):事务1和事务2之间是隔离的。
- D(durability)持久性:事务一旦结束(commit, rollback),就不可以返回。
- 事务开启方式:修改 autocommit =0,begin,transaction
- 事务结束方式:rollback,commit
事务隔离性
1. read uncommitted 读未提交的,可能会出现脏读
有事务A和事务B,操作过程中事务A没有提交,事务B可以看到事务A的操作结果
首先来看如何看隔离级别
select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+
1 row in set (0.01 sec)
修改隔离级别
set global transaction isolation level read uncommitted;
select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| READ-UNCOMMITTED |
+--------------------------------+
1 row in set (0.00 sec)
小明向店铺转账800
start transaction;
update user set money = money-800 where name = '小明';
update user set money = money+800 where name = '店铺';
店铺查账是否到账
select * from user; -- by 店铺
但是小明这时候选择rollback
rollback; -- by 小明
此时店铺主人重新查账
select * from user; -- by 店铺
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
| 3 | 小明 | 1000 |
| 4 | 店铺 | 1000 |
+----+------+-------+
4 rows in set (0.00 sec)
这里店铺和小明开启了两个不同的事务B和A,如果事务A(小明)开启之后,他的未提交数据可以被其他(店铺)用户读取,这样就会出现脏读,开发中不允许出现脏读
2. read committed 读已提交的 可能会出现不可重复读现象
先是修改隔离级别,类似上面的
小张
start transaction;
select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
| 1 | a | 900 |
| 2 | b | 1100 |
| 3 | 小明 | 1000 |
| 4 | 店铺 | 1000 |
+----+------+-------+
小王
start transaction;
insert into user values(5,'c',100);
commit;
小张
select avg(money) from user;
+------------+
| avg(money) |
+------------+
| 820.0000 |
这里小张看到平均值不是之前自己看到的,之前是1000。
虽然只能读到提交的数据,但是读取同一张的数据可能前后不一致(两个人操作)。
这也叫做不可重复读现象
3. repeatable read (默认隔离级别) 重复读 可能出现幻读
修改隔离级别和前面类似
张三:
start transaction;
王五:
start transaction;
张三:
insert into user values(6,'d',1000);
commit;
王五:
insert into user values(6,'d',1000);
张三在提交之后,王五那边不能够即使相似,当王五也插入6号数据的时候,就会报错,因为数据已经存在,但是因为repeatable read的隔离王五看不到。这就叫做幻读
事务A和事务B同时操作一张表,事务A提交的数据也不能被事务B读到,可能造成幻读
4. serializable 串行化
张三:
start transaction;
王五:
start transaction;
张三:
insert into user values(7,'e',1000);
commit;
王五:
start transaction;
select * from user;
-- 能看到7号用户已经存在
张三:
start transaction;
insert into user values(8,'f',1000);
-- 语句会被卡住
**当数据表被另外的事务操作的时候,其他事务里面的写操作是不可以操作,或者说会进入排队等待,**直到其他事务结束的时候,要在没有等待超时的情况下。
他的问题在于性能最低
四种隔离级别的性能排列
READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE
隔离级别越高,问题越少,但是性能越差