MYSQL事务

一、什么是事务

事务(Transaction) 是一组数据库操作的集合,这些操作要么全部执行成功,要么全部不执行。在MySQL中,事务确保了一组数据库操作的原子性,一致性,隔离性和持久性,简称 ACID 属性。

  • 原子性 (Atomicity):原子性指事务中的所有操作要么全部执行成功,要么全部不执行。即事务不可分割,事务中的操作要么全部完成,要么由于某种原因全部回滚。
  • 一致性 (Consistency):一致性确保事务开始前和结束后,数据库状态保持一致。事务执行过程中虽然数据库状态可能临时不一致,但最终状态必须符合预期约束。
  • 隔离性 (Isolation):隔离性保证多个事务在并发执行时互不干扰,一个事务的执行不应影响其他事务。这防止了“脏读”、“不可重复读”和“幻读”等并发问题。
  • 持久性 (Durability):持久性确保一旦事务提交,数据将被永久保存,即使系统发生崩溃,数据也不会丢失。MySQL的InnoDB引擎通过将事务记录到日志文件(如redo log)来实现持久性。

二、为什么要使用事务

使用事务的主要原因是为了保持数据的 一致性完整性。在涉及多个步骤的数据库操作中,事务能保证这些操作要么全部成功,要么全体失败,避免了数据的部分更改情况。例如,银行转账操作就需要保证事务的原子性。

三、事务的优缺点

优点

缺点
  • 数据安全性:在复杂业务操作中确保数据的完整性和一致性。
  • 错误处理:在多操作场景下简化错误的处理,出现错误时可安全回滚。
  • 并发控制:通过隔离级别和锁机制有效控制并发性,避免数据冲突。
  • 性能影响:事务处理会增加额外的系统开销,在高并发环境下可能影响效率。
  • 死锁风险:当多个事务竞争相同的资源时,可能会出现死锁,需额外处理。
  • 实现复杂:隔离级别、锁机制的引入增加了系统实现和维护的复杂性。

四、MySQL 事务的使用及主要操作示例

1. 启动事务和提交事务

在MySQL中,使用 START TRANSACTIONBEGIN 命令开启事务,使用 COMMIT 命令提交事务,将更改永久保存。

原始数据:

示例:假设在一个银行系统中进行简单的转账操作,将账户1中的100元转账到账户2。

-- 开启事务
START TRANSACTION;

-- 操作1:从账户1扣除100
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- 操作2:向账户2增加100
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;

-- 提交事务
COMMIT;

在此示例中,如果 COMMIT 成功执行,账户1和账户2的变动将永久保存到数据库中

2. 回滚事务

如果事务中的操作未能成功执行,或发生错误时,可以使用 ROLLBACK 命令将所有更改撤销,返回到事务开始之前的状态。

示例:在转账的例子中,如果账户1余额不足,会导致事务失败,则可以使用回滚来撤销操作。

START TRANSACTION;

-- 操作1:检查账户1的余额是否足够
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1 AND balance >= 100;

-- 如果扣款不成功(账户1余额不足),则执行回滚
IF ROW_COUNT() = 0 THEN
    ROLLBACK;
ELSE
    -- 操作2:向账户2增加100
    UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
    COMMIT;
END IF;

3. 设置事务的隔离级别

MySQL支持四种隔离级别,使用 SET TRANSACTION ISOLATION LEVEL 命令设置隔离级别,以控制事务之间的相互影响。隔离级别从低到高为:

  • READ UNCOMMITTED:允许“脏读”,即读到未提交的数据。
  • READ COMMITTED:只能读到已提交的数据,防止“脏读”。
  • REPEATABLE READ:确保同一事务中的多次查询结果一致,防止“不可重复读”(MySQL默认)。
  • SERIALIZABLE:最高隔离级别,完全隔离,避免“幻读”。

示例:在事务中设置隔离级别,确保在多次查询中获得一致的结果。

-- 设置事务隔离级别为 REPEATABLE READ
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 开始事务
START TRANSACTION;

-- 第一次查询
SELECT balance FROM accounts WHERE account_id = 1;

-- 其他事务对账户余额做出修改(在REPEATABLE READ下不会影响当前事务)

-- 第二次查询,结果与第一次相同
SELECT balance FROM accounts WHERE account_id = 1;

-- 提交事务
COMMIT;

在此隔离级别下,即使其他事务修改了 account_id = 1 的余额,当前事务中的两次查询结果仍然一致,避免了“不可重复读”。


4. 使用 SAVEPOINTROLLBACK TO SAVEPOINT

在复杂的事务操作中,可以使用 SAVEPOINT 创建子事务控制点。ROLLBACK TO SAVEPOINT 可以回滚到指定的保存点,从而避免回滚整个事务。

示例:假设在一个事务中进行多个更新操作,其中的某一步失败时,只回滚该步骤,而保留之前的操作。

START TRANSACTION;

-- 操作1:插入一条记录
INSERT INTO accounts (account_id, balance) VALUES (3, 500);

-- 创建保存点
SAVEPOINT savepoint1;

-- 操作2:尝试更新记录
UPDATE accounts SET balance = balance - 100 WHERE account_id = 3;

-- 模拟错误:试图对不存在的账户扣款
UPDATE accounts SET balance = balance / 0 WHERE account_id = 4;

-- 错误发生,回滚到保存点1
ROLLBACK TO SAVEPOINT savepoint1;

-- 继续执行其他操作
UPDATE accounts SET balance = balance + 50 WHERE account_id = 3;

-- 提交事务
COMMIT;

在此示例中,由于在操作3中发生了错误,ROLLBACK TO SAVEPOINT savepoint1 只撤销了从保存点1之后的操作,而保留了之前的插入操作。

5. 自动提交模式 (Auto-commit)

MySQL 默认情况下每条 SQL 语句都会自动提交,可以通过设置 AUTOCOMMIT 参数来控制是否自动提交事务。SET AUTOCOMMIT=0 关闭自动提交,从而手动控制事务的提交和回滚。

示例:关闭自动提交模式,手动控制事务。

-- 关闭自动提交
SET AUTOCOMMIT = 0;

-- 开始事务(由于关闭了自动提交,默认所有操作都在同一个事务中)
UPDATE accounts SET balance = balance + 100 WHERE account_id = 1;

-- 提交事务
COMMIT;

-- 恢复自动提交
SET AUTOCOMMIT = 1;

在此示例中,通过关闭 AUTOCOMMIT,所有操作都在同一个事务中执行,直到调用 COMMIT 提交更改。


6. 使用行锁(SELECT ... FOR UPDATE)

在事务中使用 FOR UPDATE 可以锁住查询的行,以防止其他事务对同一行的数据进行修改。InnoDB引擎支持行锁,防止并发事务发生冲突。

示例:使用 FOR UPDATE 锁住账户1的记录,确保其他事务无法修改余额,直到当前事务结束。

-- 开始事务
START TRANSACTION;

-- 查询并锁住行(SELECT ... FOR UPDATE)
SELECT balance FROM accounts WHERE account_id = 1 FOR UPDATE;

-- 执行更新操作
UPDATE accounts SET balance = balance - 200 WHERE account_id = 1;

-- 提交事务
COMMIT;

在此示例中,FOR UPDATE 锁住 account_id = 1 的行,防止其他事务同时操作该行数据,直到当前事务提交为止。

7.不同隔离级别的性能与安全


总结

MySQL 事务中的主要操作包括:

  • 开启和提交事务START TRANSACTION 开启事务,COMMIT 提交事务。
  • 回滚事务ROLLBACK 撤销事务中的所有操作。
  • 设置事务隔离级别:控制事务的隔离性,防止并发问题。
  • 使用 SAVEPOINTROLLBACK TO SAVEPOINT:在事务中创建保存点,并回滚到指定保存点。
  • 自动提交模式:通过设置 AUTOCOMMIT=0 关闭自动提交,手动控制事务。
  • 使用行锁:使用 SELECT ... FOR UPDATE 锁住记录,防止并发冲突。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

study hard_day

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值