事务的定义
数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成
事务的特性(ACID)
1:原子性:事务包含的所有操作要么全部成功,要么全部失败回滚;成功必须要完全应用到数据库,失败则不能对数据库产生影响;
2:一致性:事务执行前和执行后必须处于一致性状态,
例:用户A和用户B的前加起来一共是5000; 无论AB用户之间是如何相互转换的,事务结束后两个用户的钱加起来还是5000,这就是事务的一致性。
3:隔离性:当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不被其他事务的操作所干扰,多个并发事务之间要相互隔离;
4:持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便在数据库系统遇到故障的情况下也不会丢失事物的操作。
如果不考虑事务的隔离性,事务的并发将会导致以下四个问题:
(1)丢失更新(Mysql已经几乎能够避免这种现象的发生,故很多博客或者书籍不讨论这种情况):
丢失更新就是两个不同的事务在某一时刻对同一数据进行读取后,先后进行修改。导致第一次操作数据丢失
取款事务 | 取款事务 |
---|---|
开始事务 | 开始事务 |
查询余额为100 | |
查询余额为100 | |
转入20,余额变为120(与取款事务读取的余额数据不一样,导致了回滚) | |
提交事务 | |
取出10,余额变为90 | |
回滚,余额变为100 | 丢失更新 |
(2)脏读
A事务读到了B事务未提交的数据
取款事务 | 取款事务 |
---|---|
开始事务 | 开始事务 |
查询余额为100 | |
转入20,余额变为120 | |
读取余额,120(脏数据) | |
发生错误,回滚,余额变为100 | |
转入20,余额为140(实际应该是120) | |
提交事务 |
(3)不可重复读
一个事务前后多次读取同一数据,数据内容不一致
这个比较好理解,在A事务读取数据Data之后,事务B对Data进行修改,A再读取后发现数据不一致,导致了错误
难理解的点在于:书上和网上给的例子大多没有说明不可重复读的危害,读本身不存在什么危害,而是基于读到数据做的计算就可能出现问题。
举个例子:
事务 A:select 最近 1 个月注册的新用户,把他们的级别改成 A
事务 B:注册了一个新用户Mike,提交
事务 A:select 最近 1 个月注册的新用户,给他们发送一条私信:恭喜你升级为 A !(但Mike并没有升级为A)
(4)幻读
事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
事务的隔离级别
最高级为serializable(所有级别都能避免丢失更新)
1、事务隔离级别为不可重复读时,写数据只会锁住相应的行
2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。 3、事务隔离级别为串行化时,读写数据都会锁住整张表(只能进行读-读并发)
4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大