SQL进阶知识:三、事务控制

今天介绍下关于事务控制的详细介绍,并结合MySQL数据库提供实际例子。

在MySQL中,事务控制是确保数据库操作的原子性、一致性、隔离性和持久性(ACID)的关键机制。通过事务控制,可以将多个SQL语句组合成一个逻辑单元,要么全部成功,要么全部失败,从而保证数据的完整性和一致性。

以下是事务控制的详细介绍,包括事务的基本概念、隔离级别以及实际例子。


一、事务的基本概念

1. 事务(Transaction)

事务是一组SQL语句,这些语句要么全部成功执行,要么全部不执行。事务的目的是确保数据的完整性和一致性。

2. ACID特性

  • 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。
  • 一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
  • 隔离性(Isolation):并发执行的事务之间相互隔离,一个事务的中间状态对其他事务不可见。
  • 持久性(Durability):事务一旦提交,其结果就会永久保存到数据库中。

3. 事务的状态

  • 活跃状态(Active):事务正在执行中。
  • 部分提交状态(Partially Committed):事务中的部分操作已经完成。
  • 失败状态(Failed):事务中某些操作失败。
  • 中止状态(Aborted):事务被回滚,所有操作被撤销。
  • 完成状态(Committed):事务成功提交,所有操作被永久保存。

4. 事务的控制语句

  • BEGIN TRANSACTIONSTART TRANSACTION:开始一个新的事务。
  • COMMIT:提交事务,将事务中的所有操作永久保存到数据库中。
  • ROLLBACK:回滚事务,撤销事务中的所有操作。
  • SAVEPOINT:设置事务的保存点,可以在回滚时指定到某个保存点。

二、事务的隔离级别

事务的隔离级别决定了并发事务之间的隔离程度。MySQL支持以下四种隔离级别:

  1. READ UNCOMMITTED(未提交读)

    • 最低的隔离级别,允许读取未提交的数据(脏读)。
    • 事务可以读取其他事务未提交的数据。
  2. READ COMMITTED(提交读)

    • 只能读取其他事务已提交的数据,避免了脏读。
    • 但可能会出现不可重复读(同一个事务中,多次读取同一数据结果不同)。
  3. REPEATABLE READ(可重复读)

    • 默认的隔离级别,保证在同一个事务中多次读取同一数据结果一致。
    • 但可能会出现幻读(同一个事务中,多次读取同一范围的数据结果不同)。
  4. SERIALIZABLE(可串行化)

    • 最高的隔离级别,事务完全隔离,避免了脏读、不可重复读和幻读。
    • 但性能开销最大,因为所有事务都按顺序执行。

在MySQL中,可以通过以下命令设置隔离级别:

sql 复制代码
SET SESSION TRANSACTION ISOLATION LEVEL [隔离级别];

三、实际例子

示例1:简单的事务操作

假设有一个accounts表,记录用户的账户余额:

sql 复制代码
CREATE TABLE accounts (
    id INT PRIMARY KEY,
    balance DECIMAL(10, 2)
);
场景:从用户A的账户中转账100元到用户B的账户
sql 复制代码
-- 开始事务
START TRANSACTION;

-- 从用户A的账户中扣除100元
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 向用户B的账户中添加100元
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 提交事务
COMMIT;

解释

  • 使用START TRANSACTION开始一个新的事务。
  • 执行两个UPDATE语句,分别从用户A的账户中扣除100元,并向用户B的账户中添加100元。
  • 使用COMMIT提交事务,确保两个操作要么全部成功,要么全部失败。

示例2:事务回滚

假设在转账过程中,用户B的账户不存在,需要回滚事务。

场景:从用户A的账户中转账100元到用户B的账户,但用户B的账户不存在
sql 复制代码
-- 开始事务
START TRANSACTION;

-- 从用户A的账户中扣除100元
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 检查用户B的账户是否存在
SELECT COUNT(*) INTO @account_exists FROM accounts WHERE id = 2;

-- 如果用户B的账户不存在,回滚事务
IF @account_exists = 0 THEN
    ROLLBACK;
    SELECT 'Transaction rolled back because user B does not exist.';
ELSE
    -- 向用户B的账户中添加100元
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    COMMIT;
    SELECT 'Transaction completed successfully.';
END IF;

解释

  • 使用START TRANSACTION开始一个新的事务。
  • 执行第一个UPDATE语句,从用户A的账户中扣除100元。
  • 检查用户B的账户是否存在。
  • 如果用户B的账户不存在,使用ROLLBACK回滚事务,撤销所有操作。
  • 如果用户B的账户存在,执行第二个UPDATE语句,并使用COMMIT提交事务。

示例3:使用保存点(SAVEPOINT)

假设在复杂的事务中,需要在某些步骤设置保存点,以便在出现问题时回滚到特定的保存点。

场景:处理订单,包括扣款和发货
sql 复制代码
-- 开始事务
START TRANSACTION;

-- 扣款操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 设置保存点
SAVEPOINT before_shipping;

-- 发货操作
INSERT INTO shipments (order_id, status) VALUES (1, 'shipped');

-- 检查发货是否成功
SELECT COUNT(*) INTO @shipment_success FROM shipments WHERE order_id = 1 AND status = 'shipped';

-- 如果发货失败,回滚到保存点
IF @shipment_success = 0 THEN
    ROLLBACK TO SAVEPOINT before_shipping;
    SELECT 'Shipping failed, transaction rolled back to savepoint.';
ELSE
    -- 如果发货成功,提交事务
    COMMIT;
    SELECT 'Transaction completed successfully.';
END IF;

解释

  • 使用START TRANSACTION开始一个新的事务。
  • 执行扣款操作。
  • 使用SAVEPOINT设置一个保存点before_shipping
  • 执行发货操作,并检查发货是否成功。
  • 如果发货失败,使用ROLLBACK TO SAVEPOINT回滚到保存点,撤销发货操作,但保留扣款操作。
  • 如果发货成功,使用COMMIT提交事务。

示例4:设置隔离级别

假设需要在事务中设置隔离级别,以避免并发问题。

场景:查询用户A的账户余额,并进行扣款操作
sql 复制代码
-- 设置隔离级别为可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 开始事务
START TRANSACTION;

-- 查询用户A的账户余额
SELECT balance INTO @balance FROM accounts WHERE id = 1;

-- 扣款操作
UPDATE accounts SET balance = @balance - 100 WHERE id = 1;

-- 提交事务
COMMIT;

解释

  • 使用SET SESSION TRANSACTION ISOLATION LEVEL设置隔离级别为REPEATABLE READ
  • 开始事务,查询用户A的账户余额,并进行扣款操作。
  • 提交事务。

四、总结

事务控制是确保数据库操作一致性和完整性的关键机制。通过START TRANSACTIONCOMMITROLLBACK等语句,可以管理事务的生命周期。MySQL支持四种隔离级别,可以根据实际需求选择合适的隔离级别。保存点(SAVEPOINT)可以用于在复杂事务中回滚到特定步骤,提高事务的灵活性。

相关推荐
JOEH601 分钟前
🚀 数据库插入 1000 万数据?别再傻傻用 for 循环了!实测 5 种方式效率对比
数据库·后端
lllsure7 分钟前
【MySQL】数据分片
数据库·mysql
语落心生8 分钟前
深入doris查询计划以及io调度(五)列式存储结构 - 分析Segment格式、列数据编码
数据库
DBA小马哥11 分钟前
金仓数据库 vs 达梦:MySQL迁移谁更胜一筹?
数据库·mysql·金仓数据库·kes
Luna-player26 分钟前
那个在DG数据库中将多行指定字段的文本替换操作
数据库
それども29 分钟前
MySQL 执行计划中 filtered = 100 是什么意思
数据库·mysql
技术净胜41 分钟前
Python 连接 MySQL 数据库步骤
数据库·python·mysql
厦门辰迈智慧科技有限公司1 小时前
城市地下管网全域监测与安全防控整体解决方案
数据库·安全·物联网解决方案·地下管网监测·城市地下管网监测
小肖爱笑不爱笑1 小时前
JDBC Mybatis
数据库·mybatis
cookqq1 小时前
MySQL 5.7 大表删除部分数据:.ibd 文件会变小吗?磁盘会释放吗?
数据结构·数据库·mysql