MySQL事务学习

790 阅读5分钟

事务 Transaction

事务 是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列组成

————百度百科

ACID 事务特性

  • Atomicity原子性

    事务里面的所有操作要么全部成功,要么全部失败

  • Consistency一致性

    数据从状态A,通过事务操作,转为状态B,要求数据在状态A满足的约束对于状态B的数据一样试用

  • Durability持久性

    已经提交的事务对数据的修改,应该是永久保存在数据库中的,在数据库层面已经提交的事务不可回滚

  • Isolation隔离性

    多个事务并发执行的时候,根据某些规则,确保互不影响

隔离级别&常见问题

针对MySQL数据库而言,存在可设置的四种隔离级别(由高到低):

  • 串行化serializable:一个事务一个事务的执行
  • 可重复度repeatable-read:(MySQL默认)无论其他事务是否修改并提交了数据,在这个事务中的数据不受其他事务的影响
  • 读已提交read-commited:其他事务提交的数据,对于当前事务是可读的(其他很多数据的默认隔离级别)
  • 读未提交read-uncommited:其他事务未提交的数据,对当前事务是刻度的

串行化serializable理论(注意理论上,可能受其他未知因数影响)上可以保证数据的就绝对一致

隔离级别越高,数据库并发性能越差,数据一致性越好;隔离级越低,并发性能越好,一致性越差

本质上这是一个并发场景的共享数据问题:竞态问题(操作者数量>操作物数量)

MySQL数据库其他三个隔离可能导致的常见问题:

脏读

通俗的讲,一个事务在处理过程中读取了另外一个事务未提交的数据

操作顺序 事务A 事务B
1 transaction begin
2 transaction begin
3 select balance from account
where id = 1(结果为0)
4 update account set balance = 2
where id = 1
5 select balance from account
where id = 1(结果为2)

事务A的【5】操作读取了事务B未提交的数据,导致这个数据是不一定正确的,称为脏读

隔离级别:read-uncommited会导致这个问题

不可重复度

通俗的讲,一个事务范围内,多次查询某个数据,却得到不同的结果

操作顺序 事务A 事务B
1 transaction begin
2 transaction begin
3 select balance from account
where id = 1(结果为0)
4 update account set balance = 2
where id = 1
5 select balance from account
where id = 1(结果为0)
6 transaction commit
7 select balance from account
where id = 1(结果为2)

事务A的【3】、【5】、【7】三个步骤读取的结果不一样,这种称为不可重复读

隔离级别:read-commited会导致这个问题

幻读

事务A查询的记录条数,由于事务B的增删导致,事务A某两次读取匹配的记录数不一样

操作顺序 事务A 事务B
1 transaction begin
2 transaction begin
3 select count(*) from account
where salary > 5000(结果为10)
4 insert into account
values(5000)
6 transaction commit
7 select count(*) from account
where salary > 5000(结果为11)

事务A的【3】、【7】同样的sql匹配到不同数量的记录,称为幻读

隔离级别:repeatable-read会导致这个问题

不可重复读&幻读区别

不可重复读的重点是修改: 同样的条件,你读取过的数据,再次读取出来发现值不一样了 幻读的重点在于新增或者删除: 同样的条件,第 1 次和第 2 次读出来的记录数不一样

第一类丢失更新

事务A回滚,导致事务B的提交修改失效

操作顺序 事务A 事务B
1 transaction begin
2 transaction begin
3 查询余额1000
4 查询余额1000
5 汇入100,余额修改为1100
6 transaction commit
7 rollback

事务A的回滚导致,余额恢复为1000,事务B提交的数据更新失效

第二类丢失更新

事务A的提交,导致事务B的提交失效

操作顺序 事务A 事务B
1 transaction begin
2 transaction begin
3 查询余额1000
4 查询余额1000
5 汇入100,余额修改为1100
6 transaction commit
7 去除100,余额修改i为900
8 transaction commit

事务A的提交,将余额修改为900,导致事务B的提交数据更新失效

数据库并发问题的不完全解决

为了解决上述问题,数据库通过锁机制解决并发访问的问题。根据锁定对象不同:分为行级锁和表级锁;根据并发事务锁定的关系上看:分为共享锁定和独占锁定,共享锁定会防止独占锁定但允许其他的共享锁定。而独占锁定既防止共享锁定也防止其他独占锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定,insert、update、delete和select for update语句都会隐式采用必要的行锁定。

但是直接使用锁机制管理是很复杂的,基于锁机制,数据库给用户提供了不同的事务隔离级别,只要设置了事务隔离级别,数据库就会分析事务中的sql语句然后自动选择合适的锁。 不同的隔离级别对并发问题的解决情况如图:

隔离级别 脏读 不可重复度 幻读 第一类丢失 第二类丢失
read_uncommited
read_commited
repeatable_read
serializable

表示当前隔离级别,这种问题可能发生

金三银四

参看文章: