-- 查看当前自动提交状态(MySQL默认开启)
SHOW VARIABLES LIKE 'autocommit';
-- 创建测试表(必须使用InnoDB引擎)
CREATE TABLE account (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
balance DECIMAL(10,2) NOT NULL
) ENGINE=InnoDB;
2. 事务的完整流程
sql复制代码
-- 1. 开启事务(两种方式均可)
START TRANSACTION;
-- 或
BEGIN;
-- 2. 设置保存点(可选,用于部分回滚)
SAVEPOINT sp1;
-- 3. 执行DML操作
INSERT INTO account VALUES (1, '张三', 1000);
UPDATE account SET balance = balance - 100 WHERE id = 1;
SAVEPOINT sp2;
DELETE FROM account WHERE id = 2;
-- 4. 回滚到保存点(可选)
ROLLBACK TO SAVEPOINT sp2; -- 撤销了删除操作,但保留了之前的更新
-- 5. 提交或回滚整个事务
COMMIT; -- 持久化
-- 或
ROLLBACK; -- 回滚到事务开始前的状态
-- 设置隔离级别为 RU(全局)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 重启客户端生效
-- 终端A(事务1)
USE test_db;
BEGIN;
UPDATE account SET balance = balance + 100 WHERE id = 1;
-- 此时未提交(COMMIT)
-- 终端B(事务2)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 或使用全局设置
SELECT balance FROM account WHERE id = 1; -- 读到了加100后的数据(脏读)
代码解析:事务2读到了事务1尚未持久化的临时修改。如果事务1回滚,事务2的数据就是无效的。
🟠 读已提交(READ COMMITTED)------ 不可重复读演示
sql复制代码
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 重启客户端
-- 终端A(事务1)
BEGIN;
UPDATE account SET balance = 2000 WHERE id = 1;
COMMIT;
-- 终端B(事务2)
BEGIN;
SELECT balance FROM account WHERE id = 1; -- 第一次查询:1000(事务1未提交前)
-- 终端A此时提交了事务
SELECT balance FROM account WHERE id = 1; -- 第二次查询:2000(值发生了变化)
COMMIT;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 重启客户端
-- 终端A(事务1)
BEGIN;
UPDATE account SET balance = 3000 WHERE id = 1;
COMMIT;
-- 终端B(事务2)
BEGIN;
SELECT balance FROM account WHERE id = 1; -- 第一次查询:2000(事务1提交前)
-- 终端A此时提交了事务
SELECT balance FROM account WHERE id = 1; -- 第二次查询:依然是2000(可重复读)
COMMIT;
SELECT balance FROM account WHERE id = 1; -- 事务提交后,再次查询:3000(读取最新数据)
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 重启客户端
-- 终端A(事务1)
BEGIN;
SELECT * FROM account WHERE id = 1; -- 加共享锁(读锁)
-- 终端B(事务2)
BEGIN;
UPDATE account SET balance = 100 WHERE id = 1; -- 会被阻塞,直到事务A提交
-- 如果事务A不提交,事务B会超时或一直等待
在RR级别下,快照读(普通SELECT)与当前读(SELECT ... LOCK IN SHARE MODE 或 FOR UPDATE)表现不同。
sql复制代码
-- 设置RR级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 重启客户端
-- 事务A
BEGIN;
UPDATE account SET balance = 18 WHERE id = 1; -- 修改数据
COMMIT;
-- 事务B(在事务A提交前开启)
BEGIN;
SELECT * FROM account WHERE id = 1; -- 快照读(第一次),读到旧值(假设15)
-- 事务A此时提交
SELECT * FROM account WHERE id = 1; -- 快照读(第二次),依然读到旧值15(可重复读)
SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE; -- 当前读,读到最新值18
COMMIT;