0


MySQL 事务

优质博文:IT-BLOG-CN

一、四大特性

事务可以看作一个整体,里面的内容要么都执行成功,要么都不成功。不可能存在部分执行成功而部分执行不成功的情况。在

MySQL

中,常见的存储引擎有

InnoDB、Myisam

Memory

等。其中

InnoDB

支持事务

transaction

,而

Myisam

Memory

等不支持事务。事务用来管理

DDL

DML

DCL

操作,比如

insert

,

update

,

delete

语句,默认是自动提交的。

DDL(Data Definition Languages)语句:数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象的定义。常用的语句关键字主要包括

create

drop

alter

等。
DML(Data Manipulation Language)语句:数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性,常用的语句关键字主要包括

insert

delete

udpate

select

等。(增添改查)
DCL(Data Control Language)语句:数据控制语句,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括

grant

revoke

等。

事务的四个特性(ACID):
在这里插入图片描述

**【1】原子性

Atomicity

:** 指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况。

实现原理: undo log 实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的

sql

语句。

InnoDB

实现回滚,靠的是

undo log

:当事务对数据库进行修改时,

InnoDB

会生成对应的

undo log

;如果事务执行失败或调用了

rollback

,导致事务需要回滚,便可以利用

undo log

中的信息将数据回滚到修改之前的样子。

undo log

属于逻辑日志,它记录的是

sql

执行相关的信息。当发生回滚时,

InnoDB

会根据

undo log

的内容做与之前相反的工作:对于每个

insert

,回滚时会执行

delete

;对于每个

delete

,回滚时会执行

insert

;对于每个

update

,回滚时会执行一个相反的

update

,把数据改回去。

**【2】隔离性

Isolation

:** 一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。具体细节可以参考隔离级别。

隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们主要考虑最简单的读操作和写操作(加锁读等特殊读操作会特殊说明),那么隔离性的探讨,主要可以分为两个方面:
(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性
(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性

**【3】持久性

Durability

:** 一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,接下来的其他操作或故障不应对其有任何影响。

实现原理:

InnoDB

作为

MySQL

的存储引擎,数据是存放在磁盘中的,但如果每次读写数据都需要磁盘

IO

,效率会很低。为此,

InnoDB

提供了缓存

Buffer Pool

Buffer Pool

中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从

Buffer Pool

中读取,如果

Buffer Pool

中没有,则从磁盘读取后放入

Buffer Pool

;当向数据库写入数据时,会首先写入

Buffer Pool

Buffer Pool

中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。

Buffer Pool

的使用大大提高了读写数据的效率,但是也带了新的问题:如果

MySQL

宕机,而此时

Buffer Pool

中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。

于是,引入redo log来解决这个问题:当数据修改时,除了修改·Buffer Pool·中的数据,还会在

redo log

记录这次操作;当事务提交时,会调用

fsync

接口对

redo log

进行刷盘。如果

MySQL

宕机,重启时可以读取

redo log

中的数据,对数据库进行恢复。

redo log

采用的是

WAL(Write-ahead logging,预写式日志)

,所有修改先写入日志,再更新到

Buffer Pool

,保证了数据不会因

MySQL

宕机而丢失,从而满足了持久性要求。

既然

redo log

也需要在事务提交时将日志写入磁盘,为什么它比直接将

Buffer Pool

中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:
(1)刷脏是随机

IO

,因为每次修改的数据位置随机,但写

redo log

是追加操作,属于顺序

IO


(2)刷脏是以数据页

Page

为单位的,

MySQL

默认页大小是

16KB

,一个

Page

上一个小修改都要整页写入;而

redo log

中只包含真正需要写入的部分,无效

IO

大大减少。

**【4】一致性

Consistency

:** 事务必须使数据库从一个一致状态变换到另外一个一致状态,举一个栗子,李二给王五转账

50

元,其事务就是让李二账户上减去

50

元,王五账户上加上

50

元;一致性是指其他事务看到的情况是要么李二还没有给王五转账的状态,要么王五已经成功接收到李二的

50

元转账。而对于李二少了

50

元,王五还没加上

50

元这个中间状态是不可见的。

可以说,一致性是事务追求的最终目标:前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。

二、事务操作

MySQL

的事务操作主要有以下三种:
**【1】开启事务:

Start Transaction

:** 任何一条

DML

语句

insert

update

delete

执行,标志事务的开启命令:

BEGIN

START TRANSACTION

【2】提交事务:Commit Transaction: 成功的结束,将所有的

DML

语句操作历史记录和底层硬盘数据来一次同步命令:

COMMIT

【3】回滚事务:Rollback Transaction: 失败的结束,将所有的

DML

语句操作历史记录全部清空命令:

ROLLBACK

MySQL

中直接用

SET

来改变

MySQL

的自动提交模式:默认自动提交

--禁止自动提交set autocommit=0--开启自动提交set autocommit=1

手动提交事务案例

select @@autocommit;set autocommit=0;--模拟账户转账begin;update account set money = money -100where name ='zzx';update account set money = money +100where name ='fj';--提交事务commit;--如果转账过程中出现问题,则回滚事务rollback;

三、事务的隔离级别

**【1】读未提交

Read uncommitted

:** 一个事务可以读取另一个未提交事务的数据,最低级别,任何情况都无法保证,会造成脏读。

脏读: 脏读是指一个事务正在访问数据,并且对数据进行了修改,但是这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

**【2】读已提交

Read committed

:** 一个事务要等另一个事务提交后才能读取数据,可避免脏读的发生,会造成不可重复读。

不可重复读: 在这个事务还没有结束时,另外一个事务也访问了该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

**【3】可重复读

Repeatable read

:** 就是在开始读取数据(事务开启)时,不再允许修改操作,可避免脏读、不可重复读的发生,但是会造成幻读。

幻读: 当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

**【4】串行

Serializable

:** 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

Mysql

的默认隔离级别是

Repeatable read
-- 查看隔离级别 show variables like '%isolation%’;-- 设置隔离级别/*
set session transaction isolation level 级别字符串
级别字符串:read uncommitted、read committed、repeatable read、serializable
*/-- 设置read uncommittedsetsessiontransactionisolationlevelreaduncommitted;-- 设置read committedsetsessiontransactionisolationlevelreadcommitted;-- 设置repeatable readsetsessiontransactionisolationlevelrepeatableread;-- 设置serializablesetsessiontransactionisolationlevelserializable;
标签: mysql oracle 数据库

本文转载自: https://blog.csdn.net/zhengzhaoyang122/article/details/136611054
版权归原作者 程序猿进阶 所有, 如有侵权,请联系我们删除。

“MySQL 事务”的评论:

还没有评论