事务处理
数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。在MySQL中,事务是默认提交的。
事务的基础测试(默认隔离级别)
# 关闭当前会话的事务的默认提交
set autocommit = 0; # 0为关闭,1为开启
# 若果关闭自动提交,需要手动管理事务
# 手动提交数据,如果不提交,该数据将锁定,其他会话在提交前无法访问该数据,报错 LockTimeout ,即下文中的隔离性
commit;
# 手动回滚
rollback;
事务的隔离级别
- 读未提交(Read Uncommitted)
- 最低隔离级别:允许事务读取其他事务未提交的修改(脏读)。
- 问题:可能导致脏读、不可重复读和幻读
- 适用场景:极少使用,主要因存在数据一致性问题 ,适合对数据一致性不高的场景 。
- 读已提交(Read Committed)
- 定义:事务只能读取已提交的数据,避免脏读。
- 问题:可能发生不可重复读(同一事务多次读取相同数据时结果不一致)和幻读 (新插入数据导致查询结果变化)。
- 适用场景:大多数数据库的默认隔离级别,如Oracle 。
- 可重复读(Repeatable Read)
- 定义:确保同一事务内多次读取相同数据的一致性,通过多版本并发控制(MVCC)避免不可重复读。
- 问题:仍可能发生幻读(新插入数据导致查询结果变化)。
- 适用场景:MySQL的默认隔离级别。
- 串行化 (Serialization)
- 最高隔离级别:通过加锁机制强制事务串行执行,完全避免脏读、不可重复读和幻读。
- 问题:性能影响最大,可能导致死锁或查询超时。
- 适用场景:适合对数据一致性要求极高的场景。
事务的隔离级别测试
# 查询当前系统的默认隔离机制
mysql 5.7 之前
当前会话: select @@session.tx_isolation; 或 select @@tx_isolation;
系统全局: select @@global.tx_isolation;
mysql 5.7 之后
当前会话: select @@session.transaction_isolation; 或 select @@transaction_isolation;
系统全局: select @@global.transaction_isolation;
# 修改当前系统的默认隔离机制,加上global是全局
set [global] transaction isolation level 隔离级别
# 测试隔离级别流程
# 第一步 设置隔离级别
set global transaction isolation level Read Uncommitted;
# 第二步 关闭自动提交
set autocommit = 0;
# 第三步 开启新事务
start transaction
# 第四步 测试sql
update t_sal set sal = sal + 500 where id = 1;
update t_sal set sal = sal - 500 where id = 1;
隔离级别问题
-
脏写:本质就是事务B去修改了事务A修改过的值,但是此时事务A还没提交,所以事务A随时会回滚,导致事务B修改的值也没了
例子:事务A和事务B同时在更新一条数据,事务A先把它更新为A值,事务B紧接着就把它更新为B值。事务B更新完数据的值为B,此时事务A突然回滚了,就会用它的 undo log 日志去回滚。此时事务A一回滚,直接就会把那行数据的值更新回 NULL 值, -
脏读:一个事务会读取到另一个事务未提交的数据。(读取到未提交数据)
例子:事务A修改了数据但还未提交,事务B读取到了事务A修改的数据。然后事务A因为某些错误回滚了,这个时候事务B读取到的数据就是脏的,这就是脏读。 -
不可重复读:在同一事务内,事务两次读取到的数据是不一样的。(原数据中同一条数据被修改或被删除)
例子:事务A读取了一条数据之后,事务B修改了这条数据并提交了事务,然后事务A再次读取这条数据,就会发现两次结果不一致。这就是不可重复读。 -
幻读:事务中的同一个查询在不同的时间产生不同的行集,这个就是幻读问题。(数据总条数新增但查询结果不变)
例子:事务A向数据库添加了一条数据,然后事务B查询数据,发现事务B不管怎么查询都看不到事务A添加的数据,这就产生了幻读.
不可重复读的重点在于数据的修改。在同一个事务中,如果你读取了某些数据,然后在这个事务还未结束之前,另一个事务修改了这些数据并提交,当你再次读取同样条件下的数据时,会发现数据已经发生了变化。这就是不可重复读,因为你无法在同一个事务中重复读取到相同的数据。
例如,如果一个编辑人员在编辑文档时,读取了文档的一个段落,而在他读取的同时,作者对同一段落进行了修改并保存。当编辑人员再次读取这个段落时,就会发现内容已经不同了。这种情况下,原始的读取是不可重复的。幻读的重点在于数据的新增或删除。在同一个事务中,如果你根据某个条件进行了数据查询,然后在这个事务还未结束之前,另一个事务新增或删除了一些数据并提交,当你再次进行相同条件的查询时,会发现查询结果的记录数发生了变化。这就是幻读,因为你读取的数据集出现了“幻影”,即之前不存在的数据突然出现,或者原本存在的数据突然消失了。
例如,如果一个库存管理系统在统计某类商品数量时,读取到了100件。而在统计过程中,有新的商品入库,使得实际库存增加。当管理系统再次统计时,可能会发现商品数量变成了105件,即发生了幻读。
隔离级别问题对比
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | ✔ | ✔ | ✔ |
读已提交 | ✘ | ✔ | ✔ |
可重复读 | ✘ | ✘ | ✔ |
串行化 | ✘ | ✘ | ✘ |
面试题 事务的四大特性ACID (背过)
- 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
- 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
- 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
- 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。
事务的ACID特性是由关系数据库系统(DBMS)来实现的 ,DBMS采用日志来保证事务的原子性、一致性和持久性。
日志记录了事务对数据库所作的更新,如果某个事务在执行过程中发生错误,就可以根据日志撤销事务对数据库已做的更新,使得数据库回滚到执行事务前的初始状态。