您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

Mysql中事务是什么?有什么用?

时间:2022-08-01 15:36:40  来源:今日头条  作者:java小悠

通过这一篇文章让你彻底了解事务,文章当中提供了很多真实示例,供大家参考学习!

目录

一、什么是事务?

事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作 作为一个整体一起向系统提交 或 撤销操作请求,即这些操作要么同时成功,要么同时失败。

在关系数据库中,一个事务可以是一条SQL语句,或者一组SQL语句;

JAVA当中,一个事务可以是一个接口,也可以是service层当中的一个方法;

举例:张三给李四转账1000块钱,张三银行账户的钱减少1000,而李四银行账户的钱要增加1000。 这一组操作就必须在一个事务的范围内,要么都成功,要么都失败。

 

正常情况:转账这个操作, 需要分为以下这么三步来完成

 

异常情况:转账这个操作, 也是分为以下这么三步来完成 , 在执行第三步是报错了, 这样就导致张三减少1000块钱, 而李四的金额没变, 这样就造成了数据的不一致, 就出现问题了。

 

为了解决上述的问题,就需要通过数据的事务来完成,我们只需要 在业务逻辑执行之前开启事务,执行完毕后提交事务。如果执行过程中报错,则回滚事务,把数据恢复到事务开始之前的状态 。

 

注意: 默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐式的提交事务。

二、事务操作

光说不练肯定不行,下面我们通过sql来演示以上场景,首先演示没有事务的情况,然后再演示通过事务来控制的情况。事务控制mysql当中有两种方式,我们分别进行演示。

数据准备:

DROP TABLE IF EXISTS account;

CREATE TABLE account ( 
	id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID', 
	NAME VARCHAR ( 10 ) COMMENT '姓名', 
	money DOUBLE ( 10, 2 ) COMMENT '余额' 
) COMMENT '账户表';

INSERT INTO account ( NAME, money ) VALUES ( '张三', 2000 ),( '李四', 2000 );

1、没有事务会出现什么场景?

(1) 测试正常情况

-- 1. 查询张三余额 
select * from account where name = '张三'; 
-- 2. 张三的余额减少1000 
update account set money = money - 1000 where name = '张三'; 
-- 3. 李四的余额增加1000 
update account set money = money + 1000 where name = '李四';

 

(2) 测试异常情况

UPDATE account set money = 2000;
-- 1. 查询张三余额 
select * from account where name = '张三'; 
-- 2. 张三的余额减少1000 
update account set money = money - 1000 where name = '张三'; 
出错了.... (这里是故意整的不加注释,来模仿执行当前事务执行到中间报错了)
-- 3. 李四的余额增加1000 
update account set money = money + 1000 where name = '李四';

我们把数据都恢复到2000, 然后再次一次性执行上述的SQL语句(出错了… 这句话不符合SQL语 法,执行就会报错),检查最终的数据情况, 发现数据在操作前后不一致了。

 

2、控制事务方式一(手动提交)

mysql当中的事务默认是自动提交,什么是自动提交?

所谓自动提交就是每执行一条sql就进行提交一次。而实际我们在开发当中,往往会出现上面类似业务,多条sql同时执行,还要保证要么都成功要么都失败。而在java当中我们并没有看到过什么commit提交事务,什么rollback回滚事务的相关sql,这是因为我们使用的持久层框架都进行了封装,例如MyBatis默认就是手动提交事务。而他的commit和rollback全权由框架来管控。

什么是手动提交事务?

只要不执行commit,那么mysql会认为你所执行的sql都是在一个事务当中,当commit的时候,假如成功了就都成功了,一旦执行的sql有异常,就全部回滚!

SELECT @@autocommit ;
SET @@autocommit = 0 ;
COMMIT;
ROLLBACK;

注意:

  • 上述的这种方式,我们是修改了事务的自动提交行为, 把默认的自动提交修改为了手动提交, 此时我们执行的DML语句都不会提交,需要手动的执行commit进行提交。
  • SET @@autocommit = 0 ; 设置手动提交 是临时生效(只对当前会话有效),一旦会话关闭就没了。想要设置永久手动提交可以通过mysql的配置文件当中添加 autocommit=0 然后重启即可。

什么是会话?

会话并不是指的客户端连接,一个客户端连接可以创建多个会话,navicate应该都用过,通过下图应该会一目了然!下面两个查询界面就是两个会话!

 

sql测试:

提交事务之后会发现数据根本没修改成功,原因就是执行过程遇到了报错,然后自动会进行回滚!

-- 先改为手动提交
SET @@autocommit = 0 ;

-- 1. 查询张三余额 
select * from account where name = '张三'; 
-- 2. 张三的余额减少1000 
update account set money = money - 1000 where name = '张三'; 
出错了.... (这里是故意整的不加注释,来模仿执行当前事务执行到中间报错了)
-- 3. 李四的余额增加1000 
update account set money = money + 1000 where name = '李四';
-- 4. 提交事务 
COMMIT;

3、控制事务方式二(通过命令开启事务)

除了上面所说的改为手动提交,还有一种就是通过sql来指定我要创建一个事务,commit的时候就是事务结束当前事务的时候。

  • 开启事务: START TRANSACTION 或 BEGIN ;
  • 提交事务: COMMIT;
  • 回滚事务: ROLLBACK;

sql测试:

-- 开启事务 
start transaction 
-- 1. 查询张三余额 
select * from account where name = '张三'; 

-- 2. 张三的余额减少1000 
update account set money = money - 1000 where name = '张三'; 

-- 3. 李四的余额增加1000 
update account set money = money + 1000 where name = '李四'; 

-- 如果正常执行完毕, 则提交事务 
commit; 

-- 如果执行过程中报错, 则回滚事务(commit失败的时候会自动执行回滚,不需要我们管) 
-- rollback;

三、事务四大特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID特性 。

  • 原子性(atomicity) 。一个事务是一个不可分割的工作单位,事务中包括的操作 要么都做,要么都不做 。
  • 一致性(consistency) 。事务必须是使 数据库从一个一致性状态变到另一个一致性状态 。一致性与原子性是密切相关的。
  • 隔离性(isolation) 。一个事务的执行不能被其他事务干扰。即一个事务内部的操作和使用的数据对并发的其他事务是隔离的, 并发执行的各个事务之间不能互相干扰 。
  • 持久性(durability) 。持久性也称永久性(permanence),指一个事务一旦提交,它 对数据库中数据的改变就应该是永久性的 。接下来的其他操作或故障不应该对其有任何影响。

假设我现在去ATM机转账,将我的建设银行卡的1000块钱转到中国银行的卡里去。程序可能是这样执行的:

第一步:从建设银行卡的余额里扣除1000;

第二步:然后再从中国银行的卡的余额里增加1000。

假如在第一步执行完之后服务器宕机了,那么显然第二步将无法完成,我的建设银行卡被扣了1000,但中国银行的卡却没增加,我将白白损失了1000块钱。在数据库中,这就是所谓的“不一致性状态”。

那么如何实现“一致性”呢?

事实上,ACID中的AID都是为了实现C的。事务的最终目的就是为了实现“ 一致性 ”。如果转账的操作具有原子性,那么在中途出现错误的时候发生回滚,就不会出现不一致的情况,可见,“原子性”和“一致性”是紧密联系在一起的!

四、事务的隔离性

这里再重点提一下ACID当中的 隔离性(isolation) 。

隔离性是针对数据资源的并发访问,规定了 各个事务之间相互影响的程度 。

举例:为了疫情防控,各个城市针对于每个人的出行情况,出了对应的隔离级别,例如低风险的回老家就是3天两检,中风险的就是隔离14天,特别严重的就是集中隔离21天,等等。。。

隔离级别就是为了防止出现问题,而定的规则!

而事务的隔离性也分为了4种类型的隔离级别,这些隔离级别专门用于应对 数据资源并发访问 下不同问题的场景。(就好比上面的例子,每个隔离级别都是对应一个场景,三天两检就是对应的低风险)。

1、并发事务下会产生什么问题?

什么是并发事务?

并发事务就是多个客户端同时开启事务,或者是多个会话同时开启事务!Java当中一个接口就是一个事务,也可以称之为一次会话,接口当中包含了很多sql,当并发访问接口的时候会出现什么问题,也被称为并发事务问题。当然本篇主要以数据库并发事务产生的问题为主!

隔离级别专门用于应对 数据资源并发访问 下不同问题的场景,那么究竟有哪些问题呢?有三个:脏读、不可重复读、幻读

  • 脏读: 读到了还没有提交事务的数据,简称读未提交

举例:如果一个事务B对数据进行了更改,但是还没有提交,而另一个事务A就可以读到事务B尚未提交的更新结果。这样,当事务B进行回滚时,那么事务A开始读到的数据就是一笔脏数据。

 

  • 不可重复读: 同一个事务在事务过程中,对同一个数据进行读取操作,读取到的结果不同。

举例:事务 A 多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

 

  • 幻读: 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了 “幻影”。

 

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

如何避免:

  • 要避免脏读,需要控制在事务没有提交更新前,其他事务无法看到此事务的更新结果。
  • 要避免不可重复读,假如查询单条数据,可以通过行锁,范围查询可以进行表锁。
  • 要避免幻读,需要将整张表都锁住了。

2、事务的隔离级别

上述所说的"脏读",“不可重复读”,"幻读"这些问题,其实就是数据库读一致性问题,必须由数据库提供的事务隔离机制来进行解决。

 

  • 读未提交(Read Uncommitted): 最低的隔离级别。一个事务可以读取另一个事务没有提交的更新结果。它是性能最好,也可以说它是最野蛮的方式,因为它压根儿就不加锁,所以根本谈不上什么隔离效果,可以理解为没有隔离。
  • 读已提交(Read Committed): 一个事务的更新操作只有在提交了之后,才会被另一个事务读取到同一笔数据更新后的结果。
  • 可重复读(Repeatable Read): 在整个事务中,对同一笔数据的读取结果是相同的,不管其他事务是否同时在对这笔数据进行更新,也不管这笔更新是否提交。
  • 串行化(SERIALIZABLE): 串行化就相当于处理一个人请求的时候,别的人都等着。读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。

注意:

  • MySQL默认事务隔离级别为可重复读(RR),oracle默认事务隔离级别为读已提交(RC)。
  • MySQL存在幻读,而oracle存在不可重复读和幻读的情况!
  • 数据库的事务隔离越严格,并发副作用越小,但付出的代价越大;

命令:

show variables like 't%_isolation';
select @@session.transaction_isolation;
select @@global.transaction_isolation;

注意:早期版本的mysql中用的变量名称是tx_isolation,5.7.20版本之后,用的是transaction_isolation。

事务隔离级别分为会话和全局,会话在上面有提到过,一个客户端可以有多个会话。会话一旦关闭,设置的就失效了。可以通过以下命令针对两种进行修改, SESSION就是会话级别的 , GLOBAL全局的

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

如下示例,修改会话事务隔离级别为 READ UNCOMMITTED:

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

(1)首先演示第一种:读未提交(Read Uncommitted)

首先读未提交会出现脏读,那么我们就进行通过读未提交来演示脏读!

我们就还是以这两条数据进行演示,其次我们要进行演示并发场景,就需要两个客户端,那么我们直接通过cmd打开两个窗口 来进行连接mysql演示并发场景。

打开cmd通过命令进行连接: mysql -hlocalhost -u账号 -p密码

 

我的客户端查出来的数据是乱码的,应该是数据库编码有问题,但是这不影响我们演示

以下示例就是典型的脏读,也就是读取到了他没有提交的数据,没有提交就意味着数据并没有存到磁盘,他很有可能会进行回滚,一旦回滚,而别的客户端读到了他没提交的数据,而且还依赖这些脏数据做了别的操作,那将后果不堪设想!

 

(2)第二种:读已提交(Read Committed)

读已提交可以避免脏读,这我们就不再测试了,想测试的可以按照上面的测试方法进行测试,看看是否会有以上问题!

读已提交存在不可重复读和幻读的问题,同时也是oracle默认的隔离级别,我们重点演示不可重复读!

 

其实仔细想想不可重复读其实并不是很严重,他无非是在一个事务当中多次读取可能值不一样,但是他读出来的都是提交过后的,也就意味着永远是最新的数据,有时候未必是一件坏事!!!

(3)第三种:可重复读(Repeatable Read)

可重复读可以避免脏读和不可重复读情况,但是没办法避免幻读,所以本次重点演示幻读!

在测试这个的时候我们需要将id自增给关掉,自增的情况下不会出现这种情况!

新增的时候发现报错,原因就是id为主键唯一,但是不是新增,在新增的时候实际上数据库已经存在了id为3的数据,导致新增失败,而他在这个事务当中不管怎么去查,也查不到id为3的数据,这就是幻觉!!!

 

说白了不可重复读就是在当前事务当中,不管别的客户端操作没操作过数据,他查到的都是他开启事务之前的数据。所以他根本不可能存在脏读,也不可能存在不可重复读。

(4)第四种:串行化(Serilizable)

读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。

 

五、本章总结

本篇文章要求掌握的:

  1. mysql当中事务默认是自动提交,可以改为手动提交
  2. 在一次事务当中,假如出现异常,事务会自动进行回滚
  3. 通过以上示例,如果还不知道事务是干什么的,建议多读几次,事务知识点太重要了,特别是学习后端的兄弟们!
  4. 数据库当中,并发事务会引发什么问题?幻读、不可重复读、脏读
  5. 隔离级别就是为了解决 并发事务可能会引发的问题 而诞生的,其中分为了四种级别,我们可以根据自己系统的情况进行自由选择,事务隔离越严格,并发副作用越小,但付出的代价越大。正常开发当中一般都会采用默认的。
    四种分别是:读未提交、读已提交、不可重复读、串行化。
  6. 并发事务会引发什么问题,还有隔离级别 这两个都是面试经常会问的!!!

原文链接:
https://blog.csdn.NET/weixin_43888891/article/details/126024380?utm_source=tuicool&utm_medium=referral



Tags:Mysql   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  Search: Mysql  点击:(10)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  Search: Mysql  点击:(19)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  Search: Mysql  点击:(14)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: Mysql  点击:(29)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10  Search: Mysql  点击:(15)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  Search: Mysql  点击:(33)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  Search: Mysql  点击:(54)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  Search: Mysql  点击:(56)  评论:(0)  加入收藏
为什么高性能场景选用Postgres SQL 而不是 MySQL
一、 数据库简介 TLDR;1.1 MySQL MySQL声称自己是最流行的开源数据库,它属于最流行的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。LAMP...【详细内容】
2024-02-19  Search: Mysql  点击:(40)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  Search: Mysql  点击:(56)  评论:(0)  加入收藏
▌简易百科推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  爱可生开源社区    Tags:MySQL   点击:(10)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  爱可生开源社区  微信公众号  Tags:MySQL   点击:(19)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  MySQL学习  微信公众号  Tags:MySQL   点击:(14)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  字节跳动技术团队    Tags:ByteHouse   点击:(29)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10    dbaplus社群  Tags:MySQL   点击:(15)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  转转技术  微信公众号  Tags:MySQL   点击:(33)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  数据库干货铺  微信公众号  Tags:MySQL   点击:(54)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  编程技术汇    Tags:MySQL   点击:(56)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  数据库干货铺  微信公众号  Tags:MySQL   点击:(56)  评论:(0)  加入收藏
mysql索引失效的场景
MySQL中索引失效是指数据库查询时无法有效利用索引,这可能导致查询性能显著下降。以下是一些常见的MySQL索引失效的场景:1.使用非前导列进行查询: 假设有一个复合索引 (A, B)。...【详细内容】
2024-01-15  小王爱编程  今日头条  Tags:mysql索引   点击:(88)  评论:(0)  加入收藏
站内最新
站内热门
站内头条