目录
事务控制-方式2(START TRANSACTION|BEGIN)
事务简介
事务:是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么成功,要么失败。
注意:默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句(数据库操作语句,事务用来管理insert、update、delete语句),MySQL会立即隐式提交事务。所以,我们要想把若干的操作作为一个事务,就需要手动的开启事务,手动的提交事务,如果出现异常,要手动的回滚事务。
事务的操作
前言
演示转账操作:
- 小红账户的余额-1000
- 小黑账户的余额+1000
有账户表test_account
转账代码:
# 演示转账操作
-- 1.小红账户的余额-1000
UPDATE test_account SET money = money - 1000 WHERE account_name = '小红';
-- 2.小黑账户的余额+1000
UPDATE test_account SET money = money + 1000 WHERE account_name = '小黑';
运行后,小红和小黑的余额为:
我们发现上面两条语句已经执行成功,但如果在执行转给小黑1000元的这条语句的时候出了错,那么小红的1000元就没有落处了,所以要将这两条语句作为一个事务来处理。
MySQL中的事务默认是自动提交的,如果要控制事务有两种方式。
附带(test_account表数据准备)
CREATE TABLE test_account(
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键id',
account_name VARCHAR(10) COMMENT '账户姓名',
money INT COMMENT '余额'
);
INSERT INTO test_account(account_name, money) VALUES('小红', 2000), ('小黑', 2000);
事务的操作
事务控制-方式1(SET @@AUTOCOMMIT)
查看事务的提交方式(如果为1是自动提交,如果为0是手动提交)
# 如果为1是自动提交,如果为0是手动提交
SELECT @@AUTOCOMMIT;
注意:@@指的是查看系统的变量信息
设置事务的提交方式
# 通过SET指令,设置系统变量,去更改事务提交方式为手动
SET @@AUTOCOMMIT = 0
提交事务(如果事务的提交方式为手动,那么执行增/删/改的操作,必须提交事务,才能生效)
COMMIT;
回滚事务(如果在执行事务的时候,出现了异常,可以回滚事务)
ROLLBACK;
示例如下:
给转账操作增加事务控制,使用方式1
# 给转账操作增加事务控制
# 将事务设置为手动提交
SET @@autocommit = 0;
# 演示转账操作
-- 1.小红账户的余额-1000
UPDATE test_account SET money = money - 1000 WHERE account_name = '小红';
-- 2.小黑账户的余额+1000
UPDATE test_account SET money = money + 1000 WHERE account_name = '小黑';
# 如果事务没有报错,可提交事务
COMMIT;
# 如果事务中间有报错,那么我们就要回滚事务
-- ROLLBACK;
事务控制-方式2(START TRANSACTION|BEGIN)
开启事务(一旦写了该语句,就代表要手动控制事务)
START TRANSACTION;
# 或
BEGIN;
提交事务
COMMIT;
回滚事务(如果在执行事务的时候,出现了异常,可以回滚事务)
ROLLBACK;
示例如下:
给转账操作增加事务控制,使用方式2
# 开启事务(或者BEGIN)
START TRANSACTION;
-- 演示转账操作
-- 1.小红账户的余额-1000
UPDATE test_account SET money = money - 1000 WHERE account_name = '小红';
-- 2.小黑账户的余额+1000
UPDATE test_account SET money = money + 1000 WHERE account_name = '小黑';
# 如果事务没有报错,可提交事务
COMMIT;
-- 如果事务中间有报错,那么我们就要回滚事务
-- ROLLBACK;
事务的四大特性(简称:ACID)
事务的四大特性:
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部执行成功,要么全部执行失败;
- 一致性(Consistency):事务完成后,必须使所有的数据都保持一致的状态;
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行(比如有若干个并发事务,事务A和事务B同时在操作数据库,A事务在操作的时候不会影响事务B,事务B也不会影响事务A,它们是在独立的环境下运行的);
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的(因为数据是永久存储在磁盘中的)。
并发事务引发的问题(脏读,不可重复读,幻读)
并发事务引发问题的场景-比如:事务A和事务B同时在操作数据库或一个表的时候,所引发的问题。
并发事务引发的问题:
问题 | 描述 |
脏读 | 一个事务读到另一个事务还没有提交的数据 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取到的数据不同 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了“幻影” |
事务的隔离级别
事务的隔离级别:就是为了解决并发事务所引发的问题的
事务的隔离级别:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted 读,未提交 | P | P | P |
Read committed 读,已提交 | O | P | P |
Repeatable Read(默认) 可重复读 | O | O | P |
Serializable 串行化 | O | O | O |
注意:
- Repeatable Read(可重复读)是MySQL的默认隔离级别;Read committed(读,已提交)是Oracle的默认隔离级别。
- 该表格的意思:比如第一行表示,在Read uncommitted(读,未提交)的隔离级别下,脏读,不可重复读,幻读都可能出现;比如第三行表示,在Repeatable Read(可重复读)的隔离级别下,可解决脏读和不可重复读的问题,但幻读可能会出现。
- 该表从上到下隔离级别越来越高。注意Serializable的事务隔离级别虽然是最高的,但性能却是最差的。Read uncommitted的性能是最高的,但数据安全性是最差的。所以在选择事务的隔离级别的时候,既要权衡数据的安全性,又要考虑数据库的并发性能。
- Serialization的隔离级别可以规避所有的并发事务问题;Serialization串行化:就是在事务A操作的时候,那另一个并行事务B就得等,等到事务A执行完并提交后,事务B才能够进行操作。
- 一般采用MySQL的默认隔离级别(可重复读):Repeatable Read,不会去做修改。
查看事务的隔离级别-语法:
SELECT @@TRANSACTION_ISOLATION;
注意:@@指的是查看系统的变量信息
设置事务的隔离级别-语法:
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE};
注意:如果是SESSION表示的会话级别,表示仅针对当前客户端窗口有效;如果是GLOBAL指的是,针对所有客户端的会话窗口有效。
示例如下:
需求:查看MySQL的事务隔离级别
代码:SELECT @@TRANSACTION_ISOLATION;
运行结果,MySQL的事务隔离级别是:可重复读
需求2:仅设置当前会话的隔离级别
代码:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@TRANSACTION_ISOLATION;
运行结果,当前会话的隔离级别已经修改为READ UNCOMMITTED
模拟并发事务引发的问题
打开两个窗口登录mysql,使用test数据库,准备模拟并发事务
“脏读”问题
脏读问题只会出现在Read uncommitted这种隔离级别下。
演示在Read uncommitted的隔离级别下的脏读问题-示例如下:
“不可重复读”问题
演示在Read committed的隔离级别下的不可重复读问题-示例如下:
“幻读”问题
演示在Repeatable Read的隔离级别下的幻读问题-示例如下: