目录
一、事务简介
事务:是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体,一起向系统提交或撤销操作请求,即这些操作要么同事成功,要么同时失败。
-- 案例:一个典型事务案例是银行转账
张三要给李四转账1000元,需要3个操作:
1、查询张三账户余额
2、张三账户余额-1000
3、李四账户余额+1000
以上三个操作必须全部成功,转账事务才成功。
假如在第3个操作出现了异常,而此时张三账户余额已经减少1000元了,而李四的余额却没有增加1000元!
这是不能容忍的,所以此时需要将3个操作置于事务范围当中。
1. 开启事务
2. 如果抛出异常,则回滚事务
3. 提交事务
事务回滚时,临时修改的数据,会被恢复。
注意:默认MySQL的事务是自动提交的,也就是说,当执行一条DML与对数据库进行增删改时,MySQL会立即隐式提交事务。
因此,我们要想把若干操作放在事务范围内时,需要手动开启事务、手动提交事务,如果出现异常,需要手动进行事务回滚。
二、事务操作
-
查看/设置事务提交方式
SELECT @@autocommit;
SET @@autocommit=0;
(我尝试更改事务提交方式为手动,但是每次修改表数据,都会直接自动提交了,不知道为什么,先不管他,直接用开启事务的方式START TRANSACTION或BEGIN就不会有这个问题了)
-
开启事务
START TRANSACTION 或 BEGIN;
-
提交事务
COMMIT;
-
回滚事务
ROLLBACK;
-- --------------------- 事务案例 ----------------------
-- 张三给李四进行转账操作
-- 数据准备
USE my_database;
DROP TABLE IF EXISTS account;
# 创建账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
name VARCHAR(10) COMMENT '姓名',
money INT DEFAULT 0 COMMENT '余额'
) COMMENT '账户表';
# 插入数据
INSERT INTO account (name, money) VALUES ('张三', 2000), ('李四', 2000);
SELECT * FROM account;
# 余额恢复
UPDATE account SET money = 2000 WHERE name = '张三' OR name = '李四';
SELECT * FROM account;
-- 使用事务操作
# 查看事务提交方式
SELECT @@autocommit; # @@AUTOCOMMIT=1
# 设置事务提交方式为手动(只对当前QueryConsole生效)
SET @@autocommit=0;
SELECT @@autocommit;
# 转账操作:3个步骤
# 1、查询张三账户的余额
SELECT money FROM account WHERE name = '张三';
# 2、将张三账户的余额减1000
UPDATE account SET money = money - 1000 WHERE name = '张三';
# SELECT * FROM account;
# 3、将李四账户的余额加1000
# UPDATE account SET money = money + 1000 WHERE name = '李四';
# SELECT * FROM account;
# 假设在这里出现异常,李四的账户余额不会增加
UPDATE account SET money = money + 1000 WHERE name = '李X四';
# SELECT * FROM account;
# 提交事务
COMMIT;
SELECT * FROM account;
三、事务的四大特性(ACID)
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持状态。
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据就是永久的。
四、并发事务的问题
第一次看这个并发事务问题,感觉和多线程同步问题很像。但是又很不理解,为什么数据还没提交就能被另一事务读取到。后面看完事务的隔离级别就明白了。
问题 | 描述 |
脏读 | 一个事务读到另一个事务还没有提交的数据。 |
不可重复读 | 一个事务先后读取同一条数据,但两次读取的数据不同,称之为不可重复读。 |
幻读 | 一个事务按照条件查询数据时,没有对应的数据航,但在插入数据时,又发现这行数据已经存在,好像出现了幻影。 |
五、事务的隔离级别
用于解决事务并发问题,事务的隔离级别有以下几种:
隔离级别 | 脏度 | 不可重复读 | 幻读 |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable Read(默认) | × | × | √ |
Serializable | × | × | × |
表格从上到下,事务隔离级别越来越高,数据安全性越来越高,同时并发处理性能越来越低。
在业务开发过程中,选择事务隔离级别时,既要考虑数据的安全性,又要权衡数据的并发性能。
如何查看和设置事务隔离级别?
- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
- 设置事务隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE];