数据库-事务

什么是数据库事务

构成单一逻辑工作单元的操作集合

一个典型的数据库事务如下

1
2
3
BEGIN TRANSACTION //事务开始
SQL1...比如取款操作
COMMIT/ROLLBACK //事务提交或回滚

事务四大特性 ACID

不是所有操作都是事务,事务要有一下四个特性

  • 原子性(Atomicity)
    • 事务作为一个整体被执行,包括对数据库的操作,要么全部被执行, 要么都不执行
  • 一致性(Consistency)
    • 事务应确保数据库的状态从一个一致状态转变成另一个一致状态。一致状态是数据库中的数据应满足完整性约束
  • 隔离性(Isolation)
    • 多个事务并发执行时,一个事务的执行不应该影响其他事务的执行
  • 永久性(Durability)
    • 已被提交的事务对数据库的修改应该永久保存在数据库中

常见并发异常

1、脏读

一个事务读取到另一个事务未提交的数据

事务A 事务B
- 开始事务
开始事务
- 查询账户余额为2000元
- 取款1000元,余额被更改为1000元
查询账户余额为1000元(产生脏读) -
- 取款操作发生未知错误,事务回滚,余额变更为2000元
转入2000元,余额被更改为3000元(脏读的1000+2000) -
提交事务 -
按照正确逻辑,此时账户余额应该为4000元 -

2、不可重复读

前后多次读取,数据内容不一致

事务A 事务B
开始事务 -
第一次查询,小明的年龄为20岁 -
- 开始事务
其他操作 -
- 更改小明的年龄为30岁
- 提交事务
第二次查询,小明的年龄为30岁 -
按照正确逻辑,事务A前后两次读取到的数据应该一致 -

3、幻读

前后多次读取,数据总量不一致

事务A 事务B
开始事务 -
第一次查询,数据总量为100条 -
- 开始事务
其他操作 -
- 新增100条数据
- 提交事务
第二次查询,数据总量为200条 -
按照正确逻辑,事务A前后两次读取到的数据应该一致 -

不可重复读和幻读 区别

1、不可重复读

读取了其他事务更改的数据,针对insert和update操作

解决:使用行级锁,锁定该行,事务A多次读取操作完毕后才释放,这时候才允许其他事务更改刚才的数据

2、幻读

读取了其他事务新增的数据,针对insert和delete操作

解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放,这时候才允许其他事务新增数据

四大隔离级别

1、读未提交 READ UNCOMMITTED

1
2
3
4
5
6
7
8
1)用户B:
BEGIN TRAN
UPDATE test SET age=25 WHERE name = ‘AA’
2)用户A:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED(此句不写即默认为READ COMMITTED模式)
SELECT * FROM test(此时将查到AA的age值为25
3)用户B:
ROLLBACK(此时撤消了步骤1的UPDATE操作,则用户A读到的错误数据被称为脏读)

2、读已提交 READ COMMITTED

SQL Server和Oracle的默认隔离级别

1
2
3
4
5
6
1)用户B:
BEGIN TRAN
UPDATE test SET age=25 WHERE name = ‘AA’
2)用户A:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT * FROM test (上句设置了提交读模式,则此时将会查不到数据,显示查询等待中,直到用户B进行了ROLLBACK或者COMMIT操作后,此语句才会生效)

3、可重复读 REPEATABLE READ

MySql的默认隔离级别

1
2
3
4
在用户A的事务运行之前,先设定SQL的隔离等级为REPEATABLE READ
SQL语句为SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

用户A查询完之后,用户B将无法更新用户A所查询到的数据集中的任何数据(但是可以更新、插入和删除用户A查询到的数据集之外的数据),直到用户A事务结束才可以进行更新,这样就有效的防止了用户在同一个事务中读取到不一致的数据。

4、串行化 SERIALIZABLE

1
2
3
4
在用户A的事务运行之前,先设定SQL的隔离等级为SERIALIZABLE
语句为SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

这样在用户A的事务执行过程中,别的用户都将无法对任何数据进行更新、插入和删除的操作,直到用户A的事务回滚或者提交为止。

这是四个隔离级别中限制最大的级别:一个一个排队执行,执行效率奇差,性能开销也最大,所以应只在必要时才使用该选项。

总结

- 脏读 不可重复读 幻读
读未提交 可能 可能 可能
读已提交 可能 可能
可重复读 可能
读已提交