MySQL事务

2024-01-02 09:38:49

什么是事务?

事务是数据库管理系统( DBMS )执行过程中的一个逻辑单位 ,由一个有限的数据库操作序列构成。这里面有两个关键点 ,第一个 ,它是数据库最小的工作单元 ,是不可以再分的。第二个 ,它可能包含了一个或者一系列的 DML 语句 ,包括 insert delete update。(单条 DDL( create drop)和 DCL(grant revoke )也会有事务)

简单来说就是一个或多个语句的集合,就是事务。

事务是以数据结构+算法结合的。

当在执行事务,突发崩溃,数据库会全部回滚。

我们执行的每条命令,也算事务,只不过平常我们的事务只有一条。

完整的事务包括四个属性。

原子性(A) 一致性(C) 隔离性(I) 持久性(D) 总称ACID

只要做到ACD就能C

  1. 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个 事务从来没有执行过一样。
  2. 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完 全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工 作。
  3. 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务 并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交( Read uncommitted )、读提交( read committed )、可重复读( repeatable read )和串行化 ( Serializable )
  4. 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

事务的提交方式有两种

  1. 自动提交
  2. 手动提交

show variables like 'autocommit';查看事务提交方式(默认是自动提交)

修改默认提交方式

set autocommit=0;关闭默认提交

set autocommit=1;开启默认提交

默认提交与手动提交的区别

当我们执行更新(修改)语句时,MySQL会写入日志(mysql不会立刻刷新到硬盘,而是会写入事务日志(transaction log)中,等待合适的时机写入硬盘)重新连接后,执行后的数据依旧存在。

而手动提交时,不会自动提交,必须执行commit语句手动提交。如果发送客户端崩溃或者断开连接时,数据库会全部回滚。

注意:set autocommit=0;修改手动提交只对当前会话生效,当我们重新打开时,会默认修改为自动提交

用户手动执行事务

开启事务

start transaction与begin时相同的,同样是开启一个事务

保存点

savepoint 保存点名;(可以有多个保存点)

回滚

rollback;回滚保存点 默认全部回滚

rollback 保存点名 回滚到指定的保存点 也就是回滚至保存点不执行的时候。

注意:结束事务之后,是无法回滚的,保证了事务的持久性。

结束事务

commit;结束事务

当开启事务时,未结束事务时,客户端发生异常,mysql会自动全部回滚,这体现事务的原则性,要么全部做完,要么什么都不做。

autocommit是否自动提交是不会影响用户手动开启事务的。

存储引擎 InnoDB支持事务 MyISAM不支持事务

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性

数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

隔离级别分为:

  1. 读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的 执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多 并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。
  2. 读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默 认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离 级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。
  3. 可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行 中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。
  4. 串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)

隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表 锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等。

当一个会话事务还没结束时,另一个会话就能看到事务修改的数据,这叫脏读,一般这种会发生在读未提交级别。

隔离范围

全局隔离

select @@global.tx_isolation;

会话隔离

select @@session.tx_isolation;

默认

select @@tx_isolation;

会话隔离只会隔离当前会话

全局隔离会隔离所有会话

(设置后需要重新登录,才会生效)

读未提交【Read Uncommitted】

mysql> set global transaction isolation level read uncommitted;

设置全局为读未提交

会话1

会话2

可以看到会话1的事务还未结束,而会话2就可以查看到会话1事务执行的语句,这叫脏读。

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用。

读提交【Read Committed】

set global transaction isolation level read committed;

会话1

可以看到,会话1事务还未结束时,会话2读取不到的。

会话1

会话2

两个会话事务同时进行,会话1事务的结束,影响到了会话2的事务,原本是查不到数据的,会话1事务结束,影响到了事务2,这叫不可重复性,是个问题。

可重复读【Repeatable Read】

set global transaction isolation level repeatable read;

会话1

会话2

可以看到,即使会话1事务结束,也不会影响到会话2的事务,重复体现了隔离性

串行化【Serializale】

set global transaction isolation level serializable;

会话1

会话2

可以看到,会话同时操作一个表时,后操作的事务会被阻塞。

对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用

实际最常用的是可重复读【Repeatable Read】,mysql默认的也是可重复读,RR一般不要更改

表中可重复读会出现幻读,但在MySQL中是不会出现的。

文章来源:https://blog.csdn.net/weixin_57535054/article/details/135329009
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。