MySQL事务详解

MySQL事务详解

1. 事务与隔离级别

1.1背景为什么要用事务

问题描述

比如说,你在手机上使用一张银行卡去给你老婆转钱这就涉及到:
1.从数据库读取银行卡余额-------->2.将我的余额减去转账的金额------->3.将我修改后的余额更新到数据库----->4.去数据库中读取你老婆的银行卡余额------>5.加上你转过来的金额------>6.将更新后的数据存入数据库
此时如果执行到第三步或第五步时突然断电,那么岂不是你的账户白白扣了钱,且你老婆账户也没收到转账。

解决思路

而要解决这个问题就要保证转账业务里的所有数据库的操作是一个整体的不可分割的,要不全部执行成功要不全部执行失败,不允许整个个过程没结束时就去修改数据库中的数据。

解决方案

数据库中的[事务(Transaction)]就能达到这样的效果
我们在转账操作前先开启事务,等所有数据库操作执行完成后,才提交事务,对于已经提交的事务
来说,该事务对数据库所做的修改将永久生效,如果中途发生发生中断或错误,那么该事务期间对数据
库所做的修改将会被回滚到没执行该事务之前的状态。

1.2什么是事务

一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)。
当一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成时

  • 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行成功,要么全部执行失败
  • 在 MySQL 中只有使用了 Innodb数据库引擎的数据库或表才支持事务

事务的创建分为:

  1. 隐式事务
    事务没有明显的开启和结束的标记,如insert,update、delete语句执行时在默认情况下就是一个事务,因为默认是自动提交事务的,所有执行完后就立马自动提交事务了

  2. 显式事务
    事务具有明显的开启和结束的标记,前提是需要先设置自动提交事务为禁用,手动的提交事务或回滚事务

1.3事物的四大特性(ACID)

事务的ACID属性为:
原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency): 事务完成后,必须使所有的数据都保持一致状态,如转账的例子中双方的余额总和总是相同且正确的。
隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

1.4并发事务问题

对于同时运行多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

问题描述
脏写一个事务修改了另一个事务未提交的数据,该事务可能被回滚。
脏读一个事务读到了另一个事务还没有提交的数据。
不可重复读一个事务先后读取同一个记录,但两次读出来的数据不同
幻读一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现幻影。新插入的行为称为幻影记录
脏写

当事务二修改一条数据还没提交时,如果事务一此时也修改了相同的数据,且立即提交了,此时事务二如果回滚,那么事务一的更新将不复存在,这种现象就为脏写。在这里插入图片描述

脏读

如果一个事务「读到」了另一个「未提交事务修改过的数据」,就意味着发生了「脏读」现象。

假设有 A 和 B 这两个事务同时在处理,事务 A 先开始从数据库中读取子慕的余额数据,然后再执行更新操作,
如果此时事务 A 还没有提交事务,而此时正好事务 B 也从数据库中读取子慕的余额数据,那么事务 B 读取到的余额数据是刚才事务 A 更新后的数据,即使没有提交事务
因为事务 A 是还没提交事务的,也就是它随时可能发生回滚操作,如果在上面这种情况事务 A 发生了回滚,那么事务 B 刚才得到的数据就是过期的数据,这种现象就被称为脏读 
不可重复读

在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了「不可重复读」现象。

假设有 A 和 B 这两个事务同时在处理,事务 A 先开始从数据库中读取子慕的余额数据,
然后继续执行代码逻辑处理,在这过程中如果事务 B 更新了这条数据,并提交了事务,
那么当事务 A 再次读取该数据时,就会发现前后两次读到的数据是不一致的,这种现象就被称为不可重复读。
幻读

在一个事务内多次查询某个符合查询条件的「记录数量」,如果出现前后两次查询到的记录数量不一样的情况,就意味着发生了「幻读」现象。

假设有 A 和 B 这两个事务同时在处理,事务 A 先开始从数据库查询账户余额大于 100 万的记录,
发现共有 5 条,然后事务 B 也按相同的搜索条件也是查询出了 5 条记录。
接下来,事务 A 插入了一条余额超过 100 万的账号,并提交了事务,此时数据库超过 100 万余额的账号个数就变为 6。
然后事务 B 再次查询账户余额大于 100 万的记录,此时查询到的记录数量有 6 条,发现和前一次读到的记录数量不一样了,就感觉发生了幻觉一样,这种现象就被称为幻读。

严重程度:脏写>脏读>不可重复读>幻读

1.5事务的隔离级别

SQL标准提出了四种隔离级别来规避这些现象,隔离级别越高,性能效率就越低,四种隔离级别如下:

  • 读未提交(read uncommitted),指一个事务还没提交时,他做的变更就能被其他事务看到;
  • 读提交(read committed),指一个事务提交之后,他做的变更才能被其他事物看到;
  • 可重复读(repeatable read),指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB引擎默认的隔离级别
  • 串行化(serializable),会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果读写冲突时,后访问的事务必须等待前一个事务执行完成后才能继续执行。

隔离水平高低排序:
串行化>可重复读>读已提交>读未提交

针对不同的隔离级别,并发事务时可能发生的现象也会不同。
在这里插入图片描述
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation; 命令来查看,MySQL 8.0 该命令改为 SELECT @@transaction_isolation;

select @@transaction_isolation;

通过下面的命令改变隔离级别,Session是会话级别的改变,Global是全局改变

set [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ
COMMITTED | REPEATABLE READ | SERIALIZABLE]
set session TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
set session TRANSACTION ISOLATION LEVEL READ COMMITTED;
set session TRANSACTION ISOLATION LEVEL REPEATABLE READ;
set session TRANSACTION ISOLATION LEVEL SERIALIZABLE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值