MySQL事务

事务的特性(ACID)

  • Atomicity 原子性
    • 事务中的一组操作,要么全部成功,要么全部失败。
    • 事务的原子性通过undo日志实现
  • Consistency 一致性
    • 事务开始前和结束后,数据库的完整性没有被破坏。比如:A向B转账,不能A扣款成功,而B没有收到。
  • Isolation 隔离性
    • 多个事务并发执行时,事务之间不会互相影响。
    • 事务的隔离行由MVCC机制保证。
  • Durability 持久性
    • 事务一旦提交,对数据库的变更就是永久的。
    • 事务的永久性通过redo日志实现

MySQL事务隔离级别

  • 读未提交

最低的隔离级别,允许事务读取其他事务已修改但尚未提交的数据

  • 读已提交=>常用的隔离级别

允许事务读取其他事务已提交的数据,可以避免脏读

正常来讲,事务之间应该互不干扰,该级别允许在当前事务中读取其他事务已经修改并提交的数据

  • 可重复读 InnoDB 存储引擎的默认支持的隔离级别=>常用的隔离级别

事务中对同一字段在不同时刻读取的结果都一致,可以避免脏读和不可重复读

事务开始后第一条查询语句执行时,数据库生成所有表数据的快照数据,后续该事务中所有查询都查询的快照数据,而非数据库最新数据。
除非该事务中对某条数据做了更新操作,那么后续查询到的就是数据库更新后的值
不能解决幻读问题:如果在事务A中对事务B提交的新增数据进行更新操作,那么下次查询就可以查询到该数据

  • 可串行化

最高的隔离级别,所有事务都依次执行,可以避免脏读、不可重复读和幻读

对于同一行记录,读会加读锁,写会加写锁,当出现读写冲突时,后一个事务必须等前一个事务结束

如何选择隔离级别

并发要求高的,选择 读已提交
对数据统一要求高的,选择 可重复读
因为隔离级别越高,并发性能越低

并发事务带来的问题

  • 脏读
    事务A读取到了事务B已修改未提交的数据
    事务B中修改了数据,但事务还未提交,此时事务A就查询到了修改后的数据
  • 不可重复读主要是针对更新和删除操作
    事务内部相同语句在不同时刻读取到的值不同
    例:
    隔离级别为 读已提交 时,
    ①事务A第一次查询到的数值为5000,
    ②事务B修改数值为4500,
    ③事务A查询到的数值为5000(没有出现脏读),
    ④事务B提交事务,
    ⑤事务A再次查询到的数值就是4500,与前两次查询到的数值不同
  • 幻读主要是针对插入操作

事务A读取到了事务B已提交的数据

首先来看看 MySQL 文档是怎么定义幻读(Phantom Read)的:
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
翻译:当同一个查询在不同的时间产生不同的结果集时,事务中就会出现所谓的幻象问题。例如,如果 SELECT 执行了两次,但第二次返回了第一次没有返回的行,则该行是“幻像”行。

例:
隔离级别设置为 读已提交
①事务A按条件查询到一条数据
②事务B插入一条数据,并提交
③事务A再次查询,查到两条数据
若此时事务B回滚,那么之前事务A查到的两条数据就像幻觉一样

SQL 脚本 1 在第一次查询工资为 500 的记录时只有一条,SQL 脚本 2 插入了一条工资为 500 的记录,提交之后;SQL 脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读。

解决幻读的方法

解决幻读的方式有很多,但是它们的核心思想就是一个事务在操作某张表数据的时候,另外一个事务不允许新增或者删除这张表中的数据了。

解决幻读的方式主要有以下几种:
1. 将事务隔离级别调整为 SERIALIZABLE
2. 在可重复读的事务级别下,给事务操作的这张表添加表锁。
3. 在可重复读的事务级别下,给事务操作的这张表添加 Next-key Lock(Record Lock+Gap Lock)。

  • 脏写(更新丢失)读未提交、读已提交、可重复读 这3种隔离级别都不能解决脏写问题串行化可以解决吗??
    事务B修改了事务A已修改未提交的数据
    多个事务更新同一条数据,可能发生更新丢失
    ①事务A更新了一条数据
    ②事务B也更新了这条数据
    ③事务A回滚,把该数据回滚到之前的值,导致事务B的更新丢失
    **解决脏写的主要方式:**不要在java代码中对数据进行计算,而是通过sql语句执行计算

MySQL 命令行的默认配置中事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。如果要显式地开启一个事务需要使用命令:

START TRANSACTION。

我们可以通过下面的命令来设置隔离级别

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:

  • START TRANSACTION |BEGIN:显式地开启一个事务。
  • COMMIT:提交事务,使得对数据库做的所有修改成为永久性。
  • ROLLBACK:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值