加入收藏 | 设为首页 | 会员中心 | 我要投稿 广州站长网 (https://www.020zz.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

Mysql数据库事务

发布时间:2022-11-06 16:02:45 所属栏目:MySql教程 来源:互联网
导读: 一、前言
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说:银行系统,一个人转钱给另外一个人,这个过程应该放到一个事务中,不能因为其中一个环节失败,而导致钱的丢失,要么全

一、前言

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说:银行系统,一个人转钱给另外一个人,这个过程应该放到一个事务中,不能因为其中一个环节失败,而导致钱的丢失,要么全部成功,要么全部失败。

下面带大家了解下数据库事务的特点、事务的隔离级别以及并发事务所带来的问题等等。

二、正文

1.事务的四个特性?

从业务角度出发,对数据库的一组操作要求保持4个特征:

为了更好地理解ACID,以银行账户转账为例:

1START TRANSACTION; 2SELECT balance FROM checking WHERE customer_id = 10233276; 3UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276; 4UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276; 5COMMIT; 6 7

ACID 之间的关系

事务的 ACID 特性概念很简单,但不好理解,主要是因为这几个特性不是一种平级关系:

2.并发事务带来的问题

例如:

T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。

列如:

T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。

注:在 InnoDB 存储引擎中,SELECT 操作的不可重复读问题通过 MVCC 得到了解决,而 UPDATE、DELETE 的不可重复读问题是通过 Record Lock (行锁) 解决的,INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的。

例如:

T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。

幻读和不可重复读的区别:

并发事务处理带来的问题的解决办法:

(1)一种是加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。

(2)另一种是数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本。

更详细的关于MVCC讲解请看:MVCC详解

SQL标准定义了4类隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

3.事务的隔离级别

第1级别:Read Uncommitted(未提交读)

(1)脏读(Dirty Read):读取到了未提交的数据。

(2)不可重复读

(3)幻影读

第2级别:Read Committed(提交读)

(1)不可重复读(Nonrepeatable Read):不可重复读意味着我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。导致这种情况的原因可能有:

? (1)有一个交叉的事务有新的commit,导致了数据的改变;

? (2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit

(2)幻影读

第3级别:Repeatable Read(可重复读)

第4级别:Serializable(可串行化)

隔离级别和会导致的问题的比较

各具体数据库并不一定完全实现了上述 4 个隔离级别,例如:

上面提到了提到了行锁(Record Lock),间隙锁(Gap Lock)等,下面来详细说下。

4.锁算法

Record Lock(行锁)

锁定一个记录上的索引,而不是记录本身。

如果表没有设置索引,InnoDB 会自动在主键上创建隐藏的聚簇索引,因此 Record Locks 依然可以使用。

Gap Lock(间隙锁)

锁定索引之间的间隙,但是不包含索引本身。例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。

1SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; 2 3

Next-Key Lock

它是 Record Locks 和 Gap Locks 的结合,不仅锁定一个记录上的索引,也锁定索引之间的间隙。例如一个索引包含以下值:10, 11, 13, and 20,那么就需要锁定以下区间:

1(-, 10] 2(10, 11] 3(11, 13] 4(13, 20] 5(20, +) 6 7

在 InnoDB 存储引擎中,SELECT 操作的不可重复读问题通过 MVCC 得到了解决,而 UPDATE、DELETE 的不可重复读问题通过 Record Lock 解决,INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的。

5.事务日志?

事务日志可以帮助提高事务效率:

目前来说,大多数存储引擎都是这样实现的,我们通常称之为预写式日志(Write-Ahead Logging),修改数据需要写两次磁盘。

Mysql中的事务实现原理

事务的实现是基于数据库的存储引擎。不同的存储引擎对事务的支持程度不一样。mysql中支持事务的存储引擎有innoDB和NDB。

innoDB是mysql默认的存储引擎,默认的隔离级别是RR(Repeatable Read),并且在RR的隔离级别下更进一步,通过多版本并发控制(MVCC,Multiversion Concurrency Control )解决不可重复读问题,加上间隙锁(也就是并发控制)解决幻读问题。因此innoDB的RR隔离级别其实实现了串行化级别的效果,而且保留了比较好的并发性能。

事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。说到事务日志,不得不说的就是redo和undo。

1.redo log

在innoDB的存储引擎中,事务日志通过重做(redo)日志和innoDB存储引擎的日志缓冲(InnoDB Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA们口中常说的“日志先行”(Write-Ahead Logging)。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘。此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。

在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。所有的事务共享redo log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起。如下一个简单示例:

记录1:

记录2:

记录3:

记录4:

记录5:

2.undo log

undo log主要为事务的回滚服务。在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作。单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。

以下是undo+redo事务的简化过程

假设有2个数值,分别为A和B,值为1,2

start transaction;

记录 A=1 到undo log;

update A = 3;

记录 A=3 到redo log;

记录 B=2 到undo log;

update B = 4;

记录B = 4 到redo log;

将redo log刷新到磁盘

commit

在1-8的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

所以,redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。

5.Mysql中的事务使用

MySQL的服务层不管理事务,而是由下层的存储引擎实现。比如InnoDB。

MySQL支持本地事务的语句:

1START TRANSACTION | BEGIN [WORK] 2COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 3ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] 4SET AUTOCOMMIT = {0 | 1} 5 6

事务使用注意点:

务类型的表进行特别的处理,因为 COMMIT、ROLLBACK 只能对事务类型的表进行提交和回滚。

不同的 SAVEPOINT。需要注意的是,如果定义了相同名字的 SAVEPOINT,则后面定义的SAVEPOINT 会覆盖之前的定义。对于不再需要使用的 SAVEPOINT,可以通过 RELEASE SAVEPOINT 命令删除 SAVEPOINT, 删除后的 SAVEPOINT, 不能再执行 ROLLBACK TO SAVEPOINT命令。

自动提交(autocommit):

Mysql默认采用自动提交模式,可以通过设置autocommit变量来启用或禁用自动提交模式

InnoDB在事务执行过程中mysql数据库,使用两阶段锁协议:

随时都可以执行锁定,InnoDB会根据隔离级别在需要的时候自动加锁;

锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放。

InnoDB也支持通过特定的语句进行显示锁定(存储引擎层):

1select ... lock in share mode //共享锁 2select ... for update //排他锁 3 4

MySQL Server层的显示锁定:

1lock tableunlock table 2 3

三、总结

本章首先数据库事务的4个特性,然后讲解了并发事务带来的问题,事务的隔离级别以及每种级别下所产生的问题,最后介绍了事务日志和事务的实现原理。

最后引用我很佩服的一个人经常说的话:你知道的越多,你不知道的越多!

文章参考:

(编辑:广州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!