本教程操作环境:windows7系统、mysql8版本、Dell G3电脑。
一、什么是事务?
事务是逻辑上的一组操作,要么全执行,要么全不执行。
(资料图)
事务最经典栗子也经常被拿出来的栗子就是银行转账了。比如小明要给小红转账1000元,这个转账会涉及到两个关键操作:将小明的余额减1000元,将小红的余额减1000元。万一这两个操作之间突然出现错误,导致小明余额减少但是小红余额没有增加,这种情况是肯定不允许的。事务就是保证这两个关键操作要么都成功,要么都不成功。
二、事务的特性(ACID)
**原子性:**事务最小的执行单位,不允许分割。事务的原子性确保动作要么全部执行,要么全部不执行。**一致性:**执行事务的前后,数据保持一致。例如转账的业务中,无论事务是否成功,转账者和收款人的总额应该是不变的。**隔离性:**并发访问数据库时,一个用户的事务不应该被其他事务所影响,各并发事务之间数据库是独立的。**持久性:**一个事务被提交后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有影响。三、并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但是可能会带来以下的问题:
**脏读(Dirty read):**当一个事务正在访问数据并且对其进行了修改,但是还没提交事务,这时另外一个事务也访问了这个数据,然后使用了这个数据,因为这个数据的修改还没提交到数据库,所以另外一个事务读取的数据就是“脏数据”,这种行为就是“脏读”,依据“脏数据”所做的操作可能是会出现问题的。修改丢失(Lost of modify):是指一个事务读取一个数据时,另外一个数据也访问了该数据,那么在第一个事务修改了这个数据之后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,这种情况就被称为修改丢失。例如:事务1读取表中数据A=20
,事务2也读取A=20
,事务1修改A=A-1
,事务2也修改A=A-1
,最终结果都是19
,但是事务1的修改记录丢失了。不可重复读(Unrepeatableread):指在一个事务内多次读取同一数据,在这个事务还没结束时,另外一个事务也访问了这个数据并对这个数据进行了修改,那么就可能造成第一个事务两次读取的数据不一致,这种情况就被称为不可重复读。幻读(Phantom read):幻读与不可重复读类似,幻读是指一个事务读取了几行数据,这个事务还没结束,接着另外一个事务插入了一些数据,在随后的查询中,第一个事务读取到的数据就会比原本读取到的多,就好像发生了幻觉一样,所以称为幻读。不可重复读和幻读区别:
不可重复读的重点是修改,幻读的重点是新增或者删除。
栗子1(同样的条件,你读取过的数据,再次读取的时候不一样了):事务1中的A先生读取自己的工资是1000的操作还没结束,事务2的B先生就修改了A先生的工资为2000,A先生再次读取自己工资的时候就变成2000了,这就是不可重复读。
栗子2(同样的条件,第1次和第2次读取出来的记录条数不一样):假如某工资表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,总共查询到4条记录,这是事务2又查询了一条工资大于3000的记录,事务1再次读取查询到的记录就是5条了,这就是幻读。
四、事务隔离级别
SQL标准定义了四个隔离级别:
**读取未提交(READ-UNCOMMITTED):**最低的隔离级别,允许读取尚未提交的数据变更,可能造成脏读、不可重复读、幻读。**读取已提交(READ-COMMITTED):**允许读取并发事务已经提交的数据,可以避免脏读,但是可能造成不可重复、幻读。**可重复读(REPEATABLE-READ):**对同一字段多次读取的结果都是一致的,除非本身事务修改,可以避免脏读和不可重复读,但是可能造成幻读。**可串行化(SERIALIZABLE):**最高的隔离级别,完全服从ACID的隔离级别,所有的事务依次执行,可以避免脏读、不可重复读、幻读。隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读取未提交 | √ | √ | √ |
读取已提交 | × | √ | √ |
可重复读 | × | × | √ |
可串行化 | × | × | × |
MySQL InnoDB
存储引擎默认的事务隔离级别是可重复读(REPEATABLE-READ),可以通过命令select @@tx_isolation;
语句来查看,MySQL 8.0
该语句改为SELECT @@transaction_isolation;
mysql> SELECT @@tx_isolation;+-----------------+| @@tx_isolation |+-----------------+| REPEATABLE-READ |+-----------------+
登录后复制
MySQL InnoDB
存储引擎的可重复读并不能避免幻读,需要应用使用加锁读来保证,这加锁读使用到的机制就是Next-Key Locks
。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是读取已提交(READ-COMMITTED),InnoDB
存储引擎默认使用 REPEATABLE-READ(可重读)并不会有任何性能损失。
InnoDB
存储引擎在分布式事务的情况下一般会用到可串行化隔离级别。
? 拓展一下(以下内容摘自《MySQL 技术内幕:InnoDB 存储引擎(第 2 版)》7.7 章):
四、实际情况演示
MySQL
命令行的默认配置中事务都是自动提交的,即执行SQL
语句就会马上执行COMMIT
操作。可以用命令START TRANSACTION
开始一个事务。
我们可以通过下面命令设置事务隔离级别。
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
登录后复制
我们再来看一下我们在实际操作中使用到的一些并发控制语句:
START TRANSACTION | BEGIN
:显示的开启一个事务。COMMIT
:提交事务,使得对数据库做的所有修改成为永久性。ROLLBACK
:回滚到结束用户的事务,并撤销正在进行的所有未提交的修改。(脏读)读取未提交
(避免脏读)读取已提交
不可重复读
还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,一个事务还没有结束,就发生了 不可重复读问题。
可重复读
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ysjbfC4b-1651149978452)(https://qtspace.cn/contentimg/81.jpg)]
幻读
演示幻读出现的情况
sql 脚本 1 在第一次查询工资为 500 的记录时只有一条,sql 脚本 2 插入了一条工资为 500 的记录,提交之后;sql 脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读。
幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。
解决幻读的方法
将事务隔离级别调整为SERIALIZABLE
。在可重复读的事务级别下,给事务操作的这张表添加表锁。在可重复读的事务级别下,给事务操作的这张表添加 Next-Key Locks
。【相关推荐:mysql视频教程】
以上就是mysql事务隔离级别有哪些的详细内容,更多请关注php中文网其它相关文章!