事务的概念及特点
事务:做一件事情,有很多个步骤,这一系列的步骤操作行为就是一个事务。
事务的四大特性:
一致性:要么同时失败 同时成功,如图一例子中不会无端端多500块或少500块,一定是A账户减少500和B账户增加500同时发生,不会是A账户减少500成功而B没有增加500。
隔离性:第一个事务操作时,第二个事务来操作就需要排队,等第一个操作完再操作。两个事务之间互不影响。
事务的使用:
事务的隔离级别有四种:
脏读 | 不可重复读 | 幻读 | |
读未提交(READ UNCOMMITTED) | Y | Y | Y |
读已提交(READ COMMITTED) | N | Y | Y |
可重复读(REPEATABLE READ) | N | N | Y |
串行(SERIALIZABLE) | N | N | N |
1、READ UNCOMMITTED - 读未提交
读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。
该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该隔离级别读取到的数据称之为脏数据,把这个问题称之为脏读。
# 事务T1:启动一个事务
start transaction ;
select * from tx ;
| id | num |
| 1 | 1 |
| 2 | 2 |
# 事务T2:也启动一个事务(那么两个事务交叉了),在事务T2中执行更新语句,且不提交
start transaction ;
update tx set num = 10 where id = 1 ;
select * from tx ;
| id | num |
| 1 | 10 |
| 2 | 2 |
# 事务T1:那么这时候事务T1能看到这个更新了的数据吗?
select * from tx ;
| id | num |
| 1 | 10 | -----> 可以看到!说明我们读到了事务T2没有提交的数据
| 2 | 2 |
# 事务T2: 事务T2回滚,仍未提交
rollback ;
select * from tx ;
| id | num |
| 1 | 1 |
| 2 | 2 |
#事务T1:在事务T1里看到的也是T2没提交的数据
select * from tx ;
| id | num |
| 1 | 1 | -----> 脏读意味着我们在这个事务中(T1中),事务T2虽然没有提交,但是它任何一条
数据变化我们都能看到
| 2 | 2 |
2 、READ COMMITTED - 读已提交
读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。
由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
如:都是select * from user , t1事务在t2事务提交前读取的数据 和 t1事务在t2事务提交后读取到的数据不一样 )
# 事务T1:启动一个事务
start transaction ;
select * from tx ;
| id | num |
| 1 | 1 |
| 2 | 2 |
# 事务T2:也启动一个事务(那么两个事务交叉了),在事务T2中执行更新语句,且不提交
start transaction ;
update tx set num = 10 where id = 1 ;
select * from tx ;
| id | num |
| 1 | 10 |
| 2 | 2 |
# 事务T1:那么这时候事务T1能看到这个更新了的数据吗?
select * from tx ;
| id | num |
| 1 | 1 | --------------> 并不能看到!
| 2 | 2 | |
|
# 事务T2: 如果提交了事务T2呢? |
commit ; |-----> 相同的select语句,在不同时间执行,结果却不一样!
|
#事务T1: |
select * from tx ; |
| id | num | |
| 1 | 10 | ---------------> 因为事务T2已经提交了,所以T1中我们看到了数据变化
| 2 | 2 |
3、REPEATABLE READ - 可重复读
可重复读,是MySQL的默认事务隔离级别,它能确保同一事务多次查询的结果一致。也会有新的问题,比如此级别的事务正在执行时,另一个事务成功插入了某条数据,但是因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。说明在事务中查询不到这条信息,但是自己就是插入不进去,这就叫做幻读。
# users id 主键
1、T1 : select * from users where id = 1;
2、T2 : insert into users(id,name) values(1,'p1') ;
3、T1 : insert into users(id,name) values(1,'p1') ;
# T1 : 主事务,检测表中是否有id为1的记录,没有的话正常插入,这是我们期望的正常业务逻辑。
# T2 : 干扰事务,目的在干扰T1的正常执行。
在该隔离级别下,1、2是正常执行的,3会报错主键冲突,对于T1的业务来说是执行失败的,这里的T1就发生了幻读,因为T1读取的数据状态并不能支持他的下一步的业务,见鬼了一样。
4、SERIALIZABLE - 串行
如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供了事务之间最大限度的隔离。