- 本博客是《MySQL基础》系列博客的第十四部分,简单介绍MySQL中的事务处理,包括事务的概念、特征以及事务并发所带来的问题及事务隔离级别
- 本博客既为方便自己查看复习而作,亦为你而作,望能有所裨益
- 学习交流请联系 [email protected]
基本概念
想必大家双十一的时候都曾疯狂地剁过手,过年的时候都曾激昂地抢过火车票,如果你曾细心留意,你会发现每年这个时候一些科技媒体都会报道这些数据库是如何如何处理这些高并发事务的,也就是说所谓的事务反映出来不过是数据的变动。你提交一份订单,购买一张火车票,它背后的数据库都会提交相应的事务,以保证系统数据的准确性等。
事务是一些列DML语句的集合,即众多插入、更新、删除语句组成的一个程序执行单元
四大特征
- 原子性(Atomicity):事务是一个最小的工作单元,整个工作单元要么一起提交成功,要么一起失败回滚
- 隔离性(Isolation):数据并发的时候,一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)
- 一致性(Consistency):事务中操作的数据及状态改变是一致的,即写入资料的结果必须完全符合预设的规则,不会因为出现系统意外等原因导致状态的不一致
- 持久性(Durability):事务所做的修改就会永久保存,不会因为系统意外导致数据的丢失
事务并发
- 在实际生活中,我们不可能总是在一个事务执行完以后再执行另一个事务,更多的是同时有许多事务一起提交,而这就叫作事务并发
(试想一下,如果火车票购买只能是这个人买完了下个人才能买的话,你会遇到那种成百上千张车票在三秒内就没了的场景嘛?) - 事务并发在提高效率的同时不可避免地会产生一些问题,如:
- 脏读:一个事务访问到了另一个事务未提交的数据
假设现在有3张车票,在3个人下订单后我们更新了一下数据,即无车票;此时回家心切的小明查询车票余量,为0张,悲伤不已;但是此时我们发现那三个人的订单有问题,于是回滚了该事务,即仍有三张车票,此时就出现了脏读 - 不可重复读:一个事务读取同一条记录两次,得到的结果不一致,重点在于数据的修改
假设现在有三张车票,此时回家心切的小明查询了一下,发现还有三张车票,兴奋极了,怀疑这是不是错觉,于是重新刷新了一下,却惊奇地发现没有了!原来在他刷新的时候有三个人已经提交订单购买车票了,而小明又陷入了深深的思考中。。。 - 幻读:一个事务读取两次,得到的记录条数不一致,重点在于数据的增加或删除
(注:幻读和不可重复读大同小异,只不过其侧重点不同而已)
- 脏读:一个事务访问到了另一个事务未提交的数据
隔离级别
为了应对事务的并发所带来的问题,可以通过设置数据库的事务隔离级别来处理:
- 读未提交(read uncommitted):事务中的修改,即使没有提交,其他事务也可以看得到,会产生“脏读”、“幻读”和“不可重复读”等问题
- 读已提交(read committed):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读”,但避免不了“幻读”和“不可重复读”的问题
- 可重复读(repeatable read):保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据,避免了“脏读”和“不可重复读”的问题,但不能避免“幻读”,性能损失更大
- 串行化(serializable):最严格的级别,事务串行执行,资源消耗最大
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 可能 | 可能 | 可能 |
读已提交 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 对InnoDB不可能 |
串行化 | 不可能 | 不可能 | 不可能 |
应用示例
- 提交事务
begin; -- 开始提交事务
<语句>;
rollback; -- 出现异常则取消事务提交
commit; -- 事务提交完毕
begin; -- 开始提交事务
insert into rental(rental_date,inventory_id,customer_id,return_date,staff_id)
values('2005-05-24 23:03:39', 367, 130, '2005-06-01 22:12:39', 1); -- 注意主外键约束
insert into payment(customer_id,staff_id,rental_id,amount,payment_date)
values(130,1,16054,911,'2017-04-01 08:20:00');
rollback; -- 出现异常则取消事务提交
commit; -- 事务提交完毕
- 显示级别
select @@transaction_isolation;
- 修改级别
set session transaction isolation level <隔离级别>;
-- 隔离级别分为 read uncommitted、read committed、repeatable read、serializable
set session transaction isolation level read uncommitted;
-- 更改当前会话的事务隔离级别为读未提交