MySQL中的事务
事务
为了达成一个目的,需要进行一系列的操作,而这一系列的操作合在一起就是事务。
事务的特性
事务都具有ACID,即原子性(Automicity),一致性(Consistency),隔离性(Isolation),持久性(Durability)。
原子性:事务中的一系列操作要么都成功,要么都失败。
一致性:事务执行时从一个状态转换成另一个状态,但是整个数据的完整性保持稳定。
隔离性:事务与事务之间互相隔离。
持久性:事务完成后对数据的改变是永久的。
通过一个例子来理解事务的特性
比如一次购买行为,购买时需要扣除购买人的余额,然后给商家增加收入,最后商品发货。这一整个过程就可以称为一个事务,如果购买的过程中出现异常比如在扣除购买人余额后出现了异常导致后面的流程无法进行,则会出现购买人余额扣除但商家未收到转账,所以一个事务要保证原子性。双方余额的总数在更改前后不变,保证了其一致性。事务结束后数据在库中保存保证了持久性。
事务的隔离级别
这里的事务隔离级别是基于MySQL的InnoDB引擎。
事务的隔离级别分别有,读未提交,读提交,可重复读,串行。
其中读未提交其实就是不加事务,仅仅执行一条更新插入就是读未提交。
直接讲述概念并不能很好的理解这几种级别,下面过几个例子来进行说明。
有这么一张表:
CREATE TABLE `t` (
`id` int NOT NULL,
`a` int DEFAULT NULL,
`t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `t_modified` (`t_modified`)
) ENGINE=InnoDB;
INSERT INTO t VALUES(1,1,'2018-11-12 00:00:00');
INSERT INTO t VALUES(2,2,'2018-11-14 00:00:00');
INSERT INTO t VALUES(3,3,'2018-11-18 00:00:00');
同时有以下两个会话:
session A | session B |
---|---|
set session transaction isolation level READ COMMITTED; | |
begin; | |
select * from t where id=2;(2,2,'2018-11-14 00:00:00') | |
update t set a=4 where id=2; | |
select * from t where id=2;(2,4,'2018-11-14 00:00:00') | |
commit; |
sessionA开启了一个事务,使用的级别是读提交,set session transaction isolation level READ COMMITTED可以将当前会话的隔离级别设置为读提交,第一次查询时记录还没有变化,此时sessionB修改了id=2的这行数据,事务中再次查询得到了最新结果,在一个事务中能读取到其他事务提交的结果这就是读提交。此时会带来不可重复读与幻读的问题。在上面的例子出现的就是不可重复读,一个事务内的数据前后读取值不一致。至于幻读暂时按下不表,让我们再看一个例子。
sessionA | sessionB |
---|---|
set session transaction isolation level REPEATABLE READ; | |
begin; | |
select * from t where id=2;(2,4,'2018-11-14 00:00:00') | |
update t set a=2 where id=2; | |
select * from t where id=2;(2,4,'2018-11-14 00:00:00') | |
commit; | |
select * from t where id=2;(2,2,'2018-11-14 00:00:00') |
MySQL的默认隔离级别就是可重复读,但是依然可以使用语句显示指定隔离级别,可以看到在可重复读的级别下在事务内读取到的数据始终是不变的,这样就避免了不可重复读的情况。当需要进行一些统计时会需要用到可重复读的隔离级别,比如在一个交易系统中我想统计到当前为止的支出,并不想让最近产生的更新影响到我,此时就需要可重复读。
幻读可以理解为在一个事务执行期间读取到另外一个事务插入的行。同样的可以通过例子来说明:
sessionA | sessionB |
---|---|
begin; | 单元 2 |
select * from t where a=3 for update;(3,3,'2018-11-18 00:00:00') | |
insert into t values(4,3,'2018-12-01 00:00:00') | |
update t set a=a+1 where a=3; | |
commit; | |
select * from t where a=4;(3,4,'2018-11-18 00:00:00')(4,3,'2018-12-01 00:00:00') |
出现上述情况则是出现了幻读,可以看到sessionA修改了sessionB新插入的数据这是不应该的。
对于串行,顾名思义就是一个接一个执行,因此效率最低。
隔离级别越高,效率就越低因此效率上来说:
读未提交>读提交>可重复读>串行
总结
本文主要讲述了以下几点:
1.事务的概念,事务的ACID特性。
2.事务的隔离级别,读未提交,读提交,可重复读,串行。
3.事务的不同隔离级别下会出现的问题,脏读,不可重复读,幻读。
花了几个月时间把 MySQL 重新巩固了一遍,梳理了一篇几万字 “超硬核” 的保姆式学习教程!(持续更新中~)
民工哥赞 14阅读 1.9k
初学后端,如何做好表结构设计?
王中阳Go赞 4阅读 1.7k评论 2
Redis的线程模型和事务
KerryWu赞 6阅读 6.1k评论 2
Spring系列-实战篇(5)-数据库的事务和锁
KerryWu赞 2阅读 6k评论 1
Vue+Express+Mysql全栈项目之增删改查、分页排序导出表格功能
水冗水孚赞 4阅读 2.6k
MySQL百万数据深度分页优化思路分析
一个程序员的成长赞 7阅读 868
深入理解MySQL索引底层数据结构
京东云开发者赞 3阅读 571
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。