MySQL事务

目录

什么是事务?

事务的特性

事务的隔离级别

脏读

不可重复读

幻读

事务的使用


什么是事务?

事务:是一组操作的集合,这组操作要么全部成功,要么全部失败,以确保数据的一致性完整性

例如:

在进行转账操作时(A向B转账):

第一步:A 账户 -2000 元

第二步:B账户 +2000 元

对应 SQL:

update account set balance = balance - 2000 where name = 'A';

update account set balance = balance + 2000 where name = 'B'; 

若没有事务,第一个SQL执行成功,但在执行第二个SQL语句之前,数据库挂了,此时, A 账户中的 2000 元扣除掉,但是还未向 B 账号中转入

等待数据库恢复时,A的钱就被扣掉了,但是B并没有收到钱

此时就需要使用事务,让 A-2000 B+2000 作为一组操作,这组操作要么一起成功,要么一起失败(让所有数据恢复原样)

事务的特性

事务有四个核心的特性

(1)原子性:通过事务,将多个操作打包为一个整体

(2)一致性:在事务执行前后,数据库的状态必须保持一致,防止出现上述数据库中间出现问题,产生 钱消失了 这样的不合理的情况

(3)持久性:事务的任何修改,都是持久化存在的(写入硬盘的),无论是重启程序,还是重启主机,修改的数据都是不会丢失的

(4)隔离性:多个事务在并发执行时,可能会存在一定的问题,因此,我们就需要具体情况具体分析,判断需要当前数据尽量准确,还是希望执行速度尽可能的快

接下来,我们就来学习事务的隔离级别

事务的隔离级别

脏读

我们来看一个例子:

有两个事务A和B

事务A修改了某个数据,但是事务还未提交(告诉数据库服务器自己已经执行完毕)

此时,事务B读取了事务A修改的数据

但在事务B读取完之后,事务A再对这个数据进行了修改,然后才提交数据

即: 

在这个过程中,事务B读取到的数据并不是最终的数据,也就是一个 脏的数据

 要解决脏读问题,核心思路是降低事务的并发程度,也就是给写操作加锁,也就是写的时候不能进行读,只有等写完,并且提交事务(释放锁)之后,其他事务才能进行读取

此时就意味着,在事务A释放锁之前,事务B不能进行访问,只有等事务A释放锁之后,事务B才能读取

不可重复读

不可重复读,是在上述加写锁的前提下,可能会出现的问题

虽然我们对写加上了锁,但可以通过多个事务,多次提交的方式来修改数据

事务A先修改了数据(对写加锁,此时事务B必须等待事务A提交之后才能读取),事务A提交,事务B开始读取数据(事务B多次读取数据)

此时事务C对上述数据再次进行修改,这就导致事务B两次读取到的结果并不相同

出现上述问题是因为我们只对写加了锁,约定写的时候不能读,但是没有对读加锁,即未表明读的时候不能写,此时,也就出现了上述情况:事务B正在读取数据,事务C就将数据修改了

要解决上述问题,就需要给读加锁,约定读的时候不能写

幻读

对写加锁 对读加锁 的前提下

事务A 修改了数据,提交,事务B开始读取

此时事务C新增(或删除)了一个其他数据

事务B就可能出现两次读取的 结果集(查询出来的行数)不同

要解决幻读问题,就需要让事务A、B 和 C 串行执行,即不再有任何并发,第一个事务执行完毕,再执行第二个任务

对于上述可能出现的 脏读、不可重复读 和 幻读,并不是一定要解决的BUG,而是要根据具体的需求,看当前更关注于数据的准确性,还是更关注于效率

因此,MySQL 在配置中,提供了 隔离级别 这样的选项,我们就可以根据需求,调整隔离级别,适应不同的情况

隔离级别说明
READ UNCOMMITTED读未提交,并行程度最高,隔离程度最低;效率最高,数据最不可靠,可能会出现 脏读不可重复读 幻读 的情况
READ COMMITTED读已提交,给写加锁,并行程度降低,隔离程度提高;效率提高,数据可靠性提高,可能会出现 不可重复读 幻读 的情况
REPEATABLE READ可重复读,给读操作和写操作都加锁,并行程度更低,隔离级别更高;效率更高,数据更可靠,可能会出现 幻读 的情况
SERIALIZABLE串行化,让所有的事务都串行执行,并行程度最低,隔离级别最高;效率最低,数据最可靠

数据库默认的隔离级别为 REPEATABLE READ(可重复读)

事务的使用

事务的操作主要有:

1. 开启事务 start transaction(一组操作前开启事务)

2. 提交事务 commit(这组操作全部成功,提交事务)

3. 回滚事务 rollback(这组操作中间任意一个操作出现异常,回滚事务)

即:

开启事务

执行 SQL 语句

回滚或提交 

开启事务

start transaction;

提交

commit;

回滚

rollback;

例如:

start transaction;

update account set balance = balance - 2000 where name = 'A';

update account set balance = balance + 2000 where name = 'B'; 

commit;

事务的回滚一般不会在控制台使用,而是在 Java 代码中,控制事务的开启,接着执行 SQL 语句,在某个 SQL 语句抛出异常时,在 catch 语句中,捕获到异常,使用 rollback,进行回滚

这种情况下,是我们的程序出现了异常,而不是数据库出现了问题

评论 65
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楠枬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值