【Mysql】事务
- 一、事务的概念
- 二、事务的特性(ACID)
- 2.1 原子性(Atomicity)
- 2.2 一致性(Consistency)
- 2.3 隔离性(Isolation)
- 2.4 持久性(Durability)
- 三、为什么使用事务
- 四、使用事务
- 4.1 语法
- 4.2 语法的运用
- 开启一个事务,执行修改后回滚
- 开启一个事务,提交修改后回滚
- 4.3 保存点
- 4.4 自动/手动提交
- 五、事务的隔离级别
- 5.1 查看和设置隔离级别
- 5.2 READ UNCOMMITTED(读未提交)
- 存在问题
- 5.3 READ COMMITTED(读已提交)
- 存在问题
- 5.4 REPEATABLE READ(可重复读)
- 存在问题
- 5.5 SERIALIZABLE(串行化)
- 存在问题
- 5.6 总结四大隔离级别
一、事务的概念
事务是一组逻辑上相关的数据库操作,这些操作要么全部成功提交(commit),要么全部回滚(rollback),以保证数据库的完整性。
二、事务的特性(ACID)
2.1 原子性(Atomicity)
原子性是指事务中的所有操作要么全部成功,要么全部失败。如果事务中的某个操作失败,整个事务都会被回滚到初始状态。比如:假设账户A给账户B转账,如果账户A转账成功(账户A已经扣款成功),但是账户B接受失败(账户B加款失败),则整个事务就会回滚,账户A和账户B就会回滚到事务之前(两个账户金额都没发生改变)。
2.2 一致性(Consistency)
一致性是指事务执行前后,数据库必须处于一致的状态。事务完成后,数据应满足所有完整性约束。比如:账户A给账户B转账,账户A转账,账户B只能加款成功。
- 事务开始前,数据库中的数据必须保持一致性
- 事务正在进行中,数据可能不处于一致性
- 事务结束后,数据必须又处于一致性
2.3 隔离性(Isolation)
隔离性是指多个事务并发执行时,每个事务都好像在独立运行,互不干扰。MySQL通过事务隔离级别来控制并发事务之间的可见性。
MySQL支持以下隔离级别(从低到高):
- READ UNCOMMITTED(读未提交)
- READ COMMITTED(读已提交)
- REPEATABLE READ(可重复读)
- SERIALIZABLE(串行化)
下面会单独给大家详细介绍一遍隔离级别!!!
2.4 持久性(Durability)
- 持久性是指事务一旦提交,其对数据库的更改将永久生效,即使系统发生故障也不会丢失。
- 在MySQL中,事务提交后,数据会被写入磁盘,确保不会因系统崩溃而丢失。
三、为什么使用事务
事务是数据库系统中不可或缺的机制,它通过ACID特性确保了数据操作的完整性、一致性和可靠性。使用事务可以简化复杂业务逻辑的管理,支持并发操作,提高系统的可维护性,并满足各种业务场景对数据一致性的严格要求。因此,事务在现代数据库应用中被广泛使用。
MySQL在5.0版本之前默认不支持事务,因为其默认存储引擎MyISAM不支持事务功能。从MySQL 5.0开始,通过引入InnoDB存储引擎,MySQL开始支持事务,并且从5.1版本开始,InnoDB成为默认存储引擎。
四、使用事务
通过show engines; 查看支持事务的存储引擎。
4.1 语法
开启一个新事务:
START TRANSACTION;
或
begin;
提交当前事务,并对事务进行持久化保存:
commit;
回滚当前事务,取消对数据的修改:
rollback;
无论提交还是回滚,当前事务就会关闭!!!
4.2 语法的运用
首先先创建一个表:
create table account(
id bigint primary key auto_increment,
name varchar(255),
balance decimal(10,2) );
并且给里面插入两个数据:
INSERT INTO account(`name`, balance) VALUES('张三', 1000);
INSERT INTO account(`name`, balance) VALUES('李四', 1000);
select * from account;
开启一个事务,执行修改后回滚
将张三的balance减少100,李四的balance增加100。
代码:
start transaction;update account set balance =balance -100 where name = '张三';update account set balance =balance +100 where name = '李四';select * from account;rollback;select * from account;
开启一个事务,提交修改后回滚
将张三的balance减少100,李四的balance增加100。
代码:
begin;
update account set balance =balance -100 where name = '张三';
update account set balance =balance +100 where name = '李四';
commit;
rollback;
select * from account;
4.3 保存点
语法:
设置保存点:
SAVEPOINT savepoint_name;
撤销保存点:
RELEASE SAVEPOINT savepoint_name;
一张截图截不下,体谅一哈,谢谢!
这里发现我们设置了一个保存点savepoint1,然后我们通过 rollback to savepoint1;返回到保存点savepoiny1;如果使用rollback,则直接返回到事务开始。
4.4 自动/手动提交
默认情况下,MySQL是⾃动提交事务的,也就是说我们执⾏的每个修改操作,⽐如插⼊、更新和删
除,都会⾃动开启⼀个事务并在语句执⾏完成之后⾃动提交,发⽣异常时⾃动回滚。
查看当前事务是否是自动提交:
SHOW VARIABLES LIKE 'autocommit';
- ON:表示自动提交模式已启用。
- OFF:表示自动提交模式已禁用。
SELECT @@autocommit;
- 1:表示自动提交模式已启用。
- 0:表示自动提交模式已禁用。
通过以下sql语句可以设置自动/手动提交:
SET autocommit = 1; -- 启用自动提交
SET autocommit = 0; -- 禁用自动提交
SET SESSION autocommit = ON; -- 启用自动提交
SET SESSION autocommit = OFF; -- 禁用自动提交
以SELECT @@autocommit; 为例:
自动提交:
-- 启用自动提交
SET autocommit = 1;
-- 从张三扣款
UPDATE account SET balance = balance - 100 WHERE name = '张三';
-- 向李四加款
UPDATE account SET balance = balance + 100 WHERE name = '李四';
结果:每条UPDATE语句独立提交。如果第一条成功,第二条失败,账户1的余额会被修改,而账户2的余额不会被修改。
手动提交:
-- 禁用自动提交
SET autocommit = 0;
-- 开始事务
START TRANSACTION;
-- 从张三扣款
UPDATE account SET balance = balance - 100 WHERE name = '张三';
-- 向李四加款
UPDATE account SET balance = balance + 100 WHERE name = '李四';
-- 检查操作是否成功
-- 如果成功,提交事务
COMMIT;
-- 如果失败,回滚事务
-- ROLLBACK;
结果:两条UPDATE语句作为一个整体提交。如果第一条成功,第二条失败,整个事务会回滚,两条语句都不会生效。
但是当自己在Mysql上实验发现第二条数据出现错误,第一条数据还是执行了!这是因为MySQL的事务的提交行为 和 错误处理机制 的特点:
Mysql的错误处理机制:
MySQL在执行事务时,对于某些类型的错误(如语法错误、约束冲突等),并不会自动回滚整个事务,而是只终止当前的失败语句。这意味着,如果事务中的某个语句因为语法错误而失败,MySQL不会自动回滚之前已经成功执行的语句。
Mysql的事务的提交行为:
需要在应用程序中显式捕获错误并执行 ROLLBACK。
了解自动和手动提交可以看下此篇博客!!!(如有侵权,请联系我,必删!!!)
这里是对上面博客的自我总结:
手动提交:假设,我们将事务提交设置为手动,用户A修改了一条数据,此时用户B通过查询可以查到数据,但此时不是永久的保存。当用户A崩溃,用户B就不能查到数据。
注意:
如果开启了事务start transaction;或begin;都需要commit;才能永久保存数据,这与SET autocommit
无关系。
五、事务的隔离级别
5.1 查看和设置隔离级别
查看隔离级别:
# 全局作⽤域
SELECT @@GLOBAL.transaction_isolation;
# 会话作⽤域
SELECT @@SESSION.transaction_isolation;
设置隔离级别:
# 设置全局事务隔离级别为串行化,后续所有事务生效,不影响当前事务
# 方式一
SET GLOBAL transaction_isolation = 'SERIALIZABLE';
# 方式二
SET @@GLOBAL.transaction_isolation='SERIALIZABLE';
# 设置会话事务隔离级别为串行化,当前会话后续的所有事务⽣效,不影响当前事务,可以在任何时候执行
# 方式一
SET SESSION transaction_isolation = 'REPEATABLE-READ';
# 方式二
SET @@SESSION.transaction_isolation='REPEATABLE-READ';
# 如果不指定任何作⽤域,设置只针对下⼀个事务,随后的事务恢复之前的隔离级别
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
5.2 READ UNCOMMITTED(读未提交)
存在问题
READ UNCOMMITTED(读未提交):事务A对数据进行修改,事务B访问事务A还没提交的数据,这种情况就是“ 脏读 ”。 事务B访问了事务A rollback数据。
5.3 READ COMMITTED(读已提交)
存在问题
READ COMMITTED(读已提交):事务A第一次查询了某条记录,事务B对这条记录进行了修改并提交了,当事务A再次查询这条记录的时候,返现与第一次查询的结果不一样,这个现象叫做“ 不可重复复 ”。
5.4 REPEATABLE READ(可重复读)
存在问题
REPEATABLE READ(可重复读):事务A第一次查询了某个结果集,第二次查询得到的结果集与第一次不同,这种现象就叫“ 幻读 ”。两次查询的结果集不同。
5.5 SERIALIZABLE(串行化)
解决了所有数据安全问题,所有事务都是一个挨一个的执行,一个事务必须等上一个事务执行完才执行。
存在问题
REPEATABLE READ(可重复读):性能开销大,因为锁竞争可能导致并发性能下降。
5.6 总结四大隔离级别
不可重复读:针对一条数据。
幻读:针对的是一个结果集。
举个例子:比如一个压缩包中包含多个文件,不可重复读:修改文件内容;幻读:修改压缩包内容(新加一个文件)。