MySQL 事务详解

原文章来自我的语雀知识库

事务的作用

事务是数据库区别于文件系统的重要系统之一。事务的主要作用是保证数据库可以从一个状态转换到另一种一致状态。比如说,对于某个金融系统,在不考虑提现、充值,仅考虑转账的情况下,金融系统内的金额总额应该始终是一个定值。事务中的操作要么全部成功、要么全部失败,不能出现事务只成功一部分而导致的数据不一致问题。
事务有着极其严格的定义,即必须符合ACID特性,而其中的原子性、隔离性、持久性,终究都是为了保证数据库的一致性。
MySQL的默认隔离级别READ REPEATABLE完全遵循和满足事务的ACID特性。

ACID

Atomic 原子性

原子性是指单个数据库事务是一个不可分割的工作单元,事务中的所有操作要么全部成功、要么全部失败。因为只有这样,数据库才能从一个状态转换到另一个保持一致性约束的状态、或者保持原状态不变。
当然了,事务中的操作是程序员定义的,定义一个事务的时候,它逻辑上就得保证能让数据库从一个状态转换到另一个符合一致性约束的状态,比如说转账操作,A扣款、B增加数额,这两个操作就只能定义在一个事务中。

Isolation 隔离性

不如说是并发控制更好理解。事务是让数据库从一个状态转换到另一个符合一致性约束的最小工作单元,也就是说,逻辑上来说事务是一个原子操作,中间是不能插入其它操作的,多个事务并行,它们之间不能相互影响。但为了提高并发度,MySQL允许事务锁定一张表的子集,减小锁的粒度以提高并发度。

Durability 持久性

事务一旦提交,其对数据库的影响应该是永久性的。即使数据库层面发生故障(宕机)也能恢复数据。

Consistency 一致性

一致性是指事务提交后能将数据库从一种状态转换到另一种符合一致性约束的状态、或者事务回滚后数据库应该恢复到事务开始前的状态。
例如,一个只考虑转账的金融系统,其金额总和应该是一个定值,如果某个转账事务只进行了一半,那这种一致性就可能会被破坏。
然而,想要保持一致性,就必须保证原子性、隔离性、持久性。即,某个事务在逻辑上必须是一个原子操作、而且事务并发操作互不影响、而且事务提交后对数据库的影响应该是永久的。

事务的分类

扁平事务

最常用也是最简单的事务。在一个扁平事务中,所有操作处于同一层次,由BEGIN开始、由COMMIT或者ROLLBACK结束,中间的操作是原子性的,要么全部成功,要么全部回滚。
扁平事务的主要限制是不能提交或者回滚事务的某一部分,或者分几个步骤提交。

带保存点的扁平事务

可以在事务的执行过程中设置保存点。可以回滚到某个保存点。

分布式事务

需要在分布式环境下运行的扁平事务,访问的数据分布在网络中的不同节点。对于分布式事务,同样需要满足ACID特性,多个节点上发生的操作要么全部成功、要么全部回滚。

事务的实现

要实现事务,就需要实现ACID特性。而通过第2点可知,只要实现了原子性、持久性、隔离性,而且保证事务的定义确实能使数据库从一个状态转换到另一个满足一致性约束的状态,一致性就得以实现。其中,事务的定义是程序员进行的。

隔离性的实现

在MySQL的默认隔离级别——可重复读隔离级别下,隔离性使用锁和MVCC机制实现。实际上,隔离性说成是并发控制更容易理解,而我们知道,多个事务并发控制主要是保证并发写操作的隔离性。那么在多个事务并发地对某个事务进行写操作时,就应该加锁来保证事务之间的写操作是隔离的(详见MySQL 锁),而MVCC机制主要是实现一致性非锁定读,即读一个被排他锁锁上的记录时,可以读它的历史版本而不用等待排他锁释放。
MVCC机制依赖于undo log来实现。

持久性的实现

redo log用来实现事务的持久性。其由两部分组成:内存中的redo log buffer,是易失的、以及磁盘中的redo log file,是持久化的。
在默认的设置下,在一个事务提交之前,必须先将该事务的所有日志写入redo log file进行持久化,才算提交完成。细分其中的步骤,首先将redo log buffer写入文件系统缓存,为了确保redo log file写入磁盘,需要进行一次系统调用fsync。fsync()是一个系统调用。它用于将文件缓冲区中的数据同步到磁盘上,以确保数据的持久性。fsync取决于磁盘的性能,也就决定了事务提交的性能,从而决定了数据库的性能。
可以通过设置innodb_flush_log_at_trx_commit来控制重做日志刷新到磁盘的策略,该参数的默认值为1,表示事务提交前必须调用fsync以保证持久性。也可以放宽这个设置以提高数据库的性能,但牺牲了持久性,可能导致一些事务的日志在宕机后丢失。

原子性的实现

原子性主要依赖undo log实现。undo log主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log,这样在发生错误时,就能回滚到事务之前的数据状态。
同时,undo log结合Read View实现了MVCC机制。
undo log分为insert undo log和update undo log,其中insert操作的undo log只对当前事务可见,只为回滚操作提供支持,所以在事务提交后就可以直接删除。而update undo log除了支持回滚操作,还需要支持MVCC机制。细分下来,update undo log记录了update操作和delete操作,在事务提交后不能直接删除,事务提交后应该放入该记录的undo log链表中,等待purge线程进行最终的删除(暂时理解为,由于需要提供MVCC机制,所以需要保存一些update undo log,当这些旧版本不再需要了,就由purge线程来真正地进行删除或者修改操作,并删除冗余的update undo log)。
对于 update 操作,undo log 会记录更新前的旧值。这在回滚时可以直接重置字段值回旧值。
对于 delete 操作,undo log 不会直接记录要删除的记录,而是记录一个逻辑删除标记。回滚时需要将这个标记恢复回未删除状态。

purge

image.png

事务控制语句

image.png
image.png

关于MySQL可重复读隔离级别

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQL事务隔离级别决定了在并发环境下多个事务之间的隔离程度。MySQL提供了四个事务隔离级别,分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。以下是对这四个隔离级别的详细解释: 1. 读未提交(Read Uncommitted):这是最低级别的隔离级别。在该级别下,一个事务可以看到其他事务未提交的修改。这可能导致脏读(Dirty Read)和不可重复读(Non Repeatable Read)的问题。 2. 读已提交(Read Committed):在该级别下,一个事务只能看到其他事务已经提交的修改。这可以避免脏读的问题,但仍可能导致不可重复读的问题。 3. 可重复读(Repeatable Read):在该级别下,一个事务在执行期间能够看到同一结果集的一致性快照。这可以避免脏读和不可重复读的问题,但仍可能导致幻读(Phantom Read)的问题。 4. 串行化(Serializable):在该级别下,事务之间是完全隔离的,每个事务必须按照顺序执行。这可以避免脏读、不可重复读和幻读的问题,但也会导致并发性能的严重下降。 要查看MySQL的默认隔离级别和当前会话的隔离级别,可以使用以下命令: ```sql SELECT @@GLOBAL.tx_isolation, @@tx_isolation; ``` 请注意,MySQL 8之前可以使用上述命令,而MySQL 8及更高版本可以使用以下命令: ```sql SELECT @@global.transaction_isolation, @@transaction_isolation; ``` 这样可以查看默认的全局隔离级别和当前会话的隔离级别。这些隔离级别可以通过设置`transaction_isolation`参数来进行更改。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值