持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,[点击查看活动详情]
事务想必大家最熟悉不过了,平常工作中肯定会使用到事务,但是你知道事务的隔离级别吗?有多少种?他们的区别是什么?本篇文章将介绍事物的隔离级别使用以及区别。
在讲事务的隔离级别之前我们先来回顾一下事务的定义和事务的特性。
事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
事务处理的原则:保证所有事务都作为 一个工作单元 来执行,即使出现了故障,都不能改变这种执行方 式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ),那么这些修改就 永久 地保存下来;要么数据库管理系统将 放弃 所作的所有 修改 ,整个事务回滚( rollback )到最初状态。
事务的ACID特性:
1.原子性(atomicity): 原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
2.一致性(consistency):根据定义,一致性是指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态 。这种状态是语义上的而不是语法上的,跟具体的业务有关。那什么是合法的数据状态呢?满足 预定的约束 的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数就是一致的,不满足这个状态,数据就是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。
3.隔离性(isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰 ,即一个事务内部的操作及使用的数据对 并发 的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4.持久性(durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的 ,接下来的其他操作和数据库故障不应该对其有任何影响。
今天我讲述的就是第三点隔离性,我们先来看一个例子,假设当前有表account有字段money有2条记录,A和B,其中A有200元,B未0元,我们执行如下操作,如下图:
事务隔离级别有4种,分别是:
1. 读未提交:`read uncommitted`,可以读取其他事务未提交的数据,会有脏读的情况。
2. 读已提交:`read committed`,会有不可重复读的情况(Oracle默认隔离级别)。
3. 可重复读:`repeatable read`,会有幻读的情况(MySQL默认隔离级别)。
4. 串行化:`serializable`,最安全,但是效率最低。
新建表account,新增两条记录如下图:
1. 脏读的演示
查看当前数据库隔离级别:show variables like 'transaction_isolation';如下图:
可以看到MySQL默认是可重复读,修改为读未提交set transaction_isolation = 'read-uncommitted';如下图;
修改完隔离级别记得退出当前会话查询开启,否则不会生效,开两个窗口,相当于两个事务。
事务1操作:开启事务,a减去50,b加上50,此时事务2查询,如下图:
此时事务1操作将事务提交。事务二在查询,如下图:
事务二此时读取发现数据不一样了,这就是脏读现象。可以采用读已提交,可重复读,串行化的隔离级别避免。
- 不可重复读的演示
读已提交会出现不可重复读的情况。先将数据库隔离级别改为读已提交,
set transaction_isolation = 'read-committed';如下图:
事务1操作先查询一下id为1的记录字段money的值,如下图:
此时事务2将id为1的记录money减去50(ps:操作的时候忘记加条件,不过不影响)
此时事务1再去查询,会发现两次查询结果不一样,如下图:
这就是不可重复读现象,可以使用可重复读,串行化隔离级别解决。
3.幻读现象
可重复读会出现幻读现象,先将数据库隔离级别改为可重复读:set gloabl transaction_isolation = 'repeatable-read';如下图:
事务1先开启事务,然后查询account表发现有两条记录,如下图:
此时事务2向数据库新增一条记录,并提交,如下图:
此时事务1再去查询数据库,会发现并没有多一条记录,如下图:
此时事务1出现幻读,明明事务2提交了去看不到数据。可以使用
串行化隔离级别解决。