事务是逻辑上的一组操作,要么全执行,要么全不执行。
事务最经典栗子也经常被拿出来的栗子就是银行转账了。比如小明要给小红转账1000元,这个转账会涉及到两个关键操作:将小明的余额减1000元,将小红的余额减1000元。万一这两个操作之间突然出现错误,导致小明余额减少但是小红余额没有增加,这种情况是肯定不允许的。事务就是保证这两个关键操作要么都成功,要么都不成功。
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但是可能会带来以下的问题:
A=20
,事务2也读取A=20
,事务1修改A=A-1
,事务2也修改A=A-1
,最终结果都是19
,但是事务1的修改记录丢失了。不可重复读的重点是修改,幻读的重点是新增或者删除。
栗子1(同样的条件,你读取过的数据,再次读取的时候不一样了):事务1中的A先生读取自己的工资是1000的操作还没结束,事务2的B先生就修改了A先生的工资为2000,A先生再次读取自己工资的时候就变成2000了,这就是不可重复读。
栗子2(同样的条件,第1次和第2次读取出来的记录条数不一样):假如某工资表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,总共查询到4条记录,这是事务2又查询了一条工资大于3000的记录,事务1再次读取查询到的记录就是5条了,这就是幻读。
SQL标准定义了四个隔离级别:
隔离级别
脏读
不可重复读
幻读
读取未提交
√
√
√
读取已提交
×
√
√
可重复读
×
×
√
可串行化
×
×
×
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 章):
InnoDB存储引擎提供了对XA事务的支持,并通过XA事务来支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源参与到一个全局的事务中。事务资源通常是关系型数据库系统,但也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对事务的原有ACID要求又有了提高。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为 SERIALIZABLE。
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.cnhttps://1000bd.com/contentImg/81.jpg)]
演示幻读出现的情况
sql 脚本 1 在第一次查询工资为 500 的记录时只有一条,sql 脚本 2 插入了一条工资为 500 的记录,提交之后;sql 脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读。
幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。
解决幻读的方法
SERIALIZABLE
。Next-Key Locks
。说明:
Next-Key Locks
相当于 行锁 + 间隙锁
参考:https://javaguide.cn/database/mysql/transaction-isolation-level.html
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦