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)可以用于在复杂事务中回滚到特定步骤,提高事务的灵活性。

相关推荐
Elastic 中国社区官方博客5 分钟前
Elasticsearch 堆内存使用情况和 JVM 垃圾回收
大数据·jvm·数据库·elasticsearch·搜索引擎·全文检索
涛思数据(TDengine)25 分钟前
时序数据库 TDengine 助力石油石化业务, 平滑接替 Oracle 数据库
数据库·时序数据库·tdengine
elastic_solr1 小时前
医药采购系统平台第10天02:按药品分类的统计&按供货商统计&按医院统计&统计数据的导出&DWR的配置和应用
大数据·数据库
·薯条大王2 小时前
Node.js 开发用户登录功能(使用mysql实现)
数据库·mysql·node.js
朴拙数科3 小时前
基于Python将MongoDB文本数据通过text2vec-large-chinese模型向量化并存储到Milvus数据库的完整实现方案
数据库·python·mongodb
咸鱼睡不醒_3 小时前
CentOS7安装MySQL教程
数据库·mysql
E___V___E3 小时前
黑马点评redis改 part 5
数据库·redis·缓存
打码人的日常分享4 小时前
网络安全风险评估报告书模版(Word)
运维·数据库·微服务·制造·需求分析
ONETHING_CLOUD_24 小时前
设备存储空间不足怎么办?
数据库·电脑·备份·数据存储·网盘·存储空间·数码知识