MySQL--事务

一、使用事务的原因

再很多情况下,我们需要执行一组操作,这一组操作要么全部失败,要么全部成功。比如银行转账,一个用户给另一个用户转账,该用户扣款,另一个用户增加余额。试想一下,如果这个用户转账后 MySQL服务器 崩溃或者其他什么原因导致另一个用户没有增加余额,就成了事故了,这个情况下就体现了事务的作用。

实例:

sql 复制代码
// 准备测试表
drop table if exists accout;
create table accout(
id int primary key auto_increment,
name varchar(20) comment '账户名称',
money decimal(11,2) comment '金额'
);
insert into accout(name, money) values
('阿里巴巴', 5000),
('四十大盗', 1000);

比如说,四十大盗从阿里巴巴账户上偷盗了2000元。

sql 复制代码
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';

例如在执行上述第一条 SQL 时,出现网络错误,或是数据库挂掉了,阿里巴巴的账户会减少2000元,但是四十大盗的账户上就没有增加金额。

解决方案:使用事务来控制,保证以上两条SQL要么全部成功,要么全部失败。

sql 复制代码
start transaction;
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';
commit;

二、回滚机制

上述我们知道了使用MySQL的事务可以确保一组SQL要么全部成功,要么全部失败,那么它是怎么确保这个操作的。这就引出了回滚机制。总的来说就是事务提交后,这一组SQL中有任何一条执行失败,它都会进行回滚,使数据库的状态回到事务执行之前的状态。

为了实现回滚机制,数据库会在执行事务的时候记录日志,当事务最终都执行完毕,中间没有差错时,这些记录的内容就可以不要了,但是在执行事务的过程中出现了问题,MySQL就可以通过日志中记录的内容来进行恢复操作。

1)之前进行了新增操作,就把数据删除

2) 之前进行了删除操作,就把数据新增回来

3) 之前进行了修改操作,就把数据改回来

4) 之前是查询操作,不影响,不需要任何回复行为

三、事务的基本特性

3.1 原子性

综上所述,我们知道所谓事务,就是将多个要执行的SQL打包成一个"整体",这个"整体"在执行过程中就能保证,要么都执行完,要么一个都不执行,不会出现执行一半的中间状态。这个特性就是事务的原子性。

3.2 一致性

执行事务之前和执行事务完毕之后的数据时一致的(不会出现"对不上"的情况)。也是和回滚有关的,一旦触发了回滚,回滚回去的数据得是对的,如果顺利执行没有触发回滚,数据也是要符合要求的。也就是对"数据正确"的承诺。

3.3 持久性

持久性就是把数据存储在硬盘上,在程序重启|主机重启后,数据仍然存在。事务的持久性就是,执行事务对数据库产生的修改,就会在硬盘上持久保存,重启之后仍然存在。

3.4 隔离性

在谈MySQL事务的隔离性之前,我们先谈在并发场景下,MySQL事务可能会存在的问题。主要是以下几个问题

3.4.1 脏读问题

试想以下,有两个事务,事务A&事务B并发执行,事务A在针对某个表的数据进行修改,与此同时,事务B读取这个表的数据就会读到事务A提交之前的临时数据,事务B读取之后事务A又把数据修改了。这样事务B读取到的数据就是临时性的数据,也就是"脏数据"。解决脏读问题的关键就在于针对写操作加锁,在写数据时不能同时读数据。

3.4.2 不可重复读问题

此时有三个事务A,B,C,事务A针对某个表的数据进行修改,在事务A执行提交之后,事务B执行开始读取这个表的数据,在事务B读取的过程,事务C又针对这个表的数据进行修改,这样就会导致事务B一开始读到的数据与之后读到的数据是不同的。解决这个问题就可以针对读操作再加锁,让其在读数据时不能进行写操作。

3.4.3 幻读问题

还是三个事务A,B,C,事务A针对某个表的数据进行修改,在事务A执行提交之后,事务B执行开始读取这个表的数据,在事务B读取的过程,事务C针对这个表进行新增操作,这样事务B前后读取的数据虽然一样了,但是结果集不同。解决幻读问题需要完全的串行执行事务,也就是基本失去了并发能力。

MySQL的事务提供了四个级别,是可以通过配置文件进行配置的。

1)read uncommitted:允许读取其他事务未提交的数据(脏读+不可重复读+幻读 并发程度最高,隔离性最低)

2)red committed:只能读取其他事务提交后的数据 (解决了脏读问题,存在不可重复读+幻读 并发程度降低,隔离性提高)

3)repeatable red:针对读写操作都加锁 (解决了脏读和不可重复读问题存在幻读 并发程度又降低,隔离性又提高)

4)串行化(serializable)所有的事务都是串行执行的 (解决了脏读不可重复读幻读问题,并发基本没有,隔离性最高)。

相关推荐
0xDevNull2 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花2 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸2 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain2 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希3 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神3 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员3 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java3 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿3 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴4 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存