一、事务简介

  • 事务是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,这些操作要么同时成功,要么同时失败。

  • 默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。

二、事务的ACID特性

  • 原子性(Atomicity):

    • 事务是数据库逻辑工作单位(最小操作单元),事务中包括的诸操作要么都做(全部成功),要么都不做(全部失败)。

    • 事务在执行过程中发生错误会被回滚(Rollback)到事务开始前的状态,就像这个事务从未执行过一样。

  • 一致性(Consistency):

    • 事务必须使数据库从一个一致性状态变换到另一个一致性状态。

    • 一致性与原子性是密切相关的。

    • 原子性保证了事务的完整性

    • 而一致性则保证了数据库系统中所有数据的内在关系正确性,不会因为事务的执行而破坏。

  • 隔离性(Isolation):

    • 数据库系统提供一定的隔离机制,使得事务在不受外部并发操作影响的“独立”环境执行。

    • 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

  • 持久性(Durability):

    • 事务一旦被提交,它对数据库的改变就是永久性的,接下来的其他操作和数据库故障不对其有任何影响。

三、事务操作方式一

  • 查看事务提交方式

SELECT @@autocommit;
/*
如果值为0,提交方式为手动提交
如果值为1,提交方式则为自动提交
*/

  • 设置事务提交方式

#设置提交方式为手动提交
SET @@autocommit = 0;

#设置提交方式为自动提交
SET @@autocommit = 1;

  • 提交事务

#将事务的提交方式设置成手动提交后,提交事务就要使用以下指令
COMMIT;
  • 回滚事务

#如果事务在执行过程中出现异常,则可以通过以下指令回滚操作
ROLLBACK;

正常事务演示

  • 基础环境准备(建表,插入数据)

CREATE TABLE account (  
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',  
    name VARCHAR(10) COMMENT '姓名',  
    money INT COMMENT '余额'  
) COMMENT='账户表';

INSERT INTO account(id, name, money) VALUES   
(null, '张三', 2000),  
(null, '李四', 2000);

  • 转账操作(张三给李四转账1000)

#查询张三账户余额
SELECT * FROM account WHERE name ='张三';

#将张三账户余额-1000
UPDATE account SET money=money-1000 WHERE name ='张三';

#将李四账户余额+1000
UPDATE account SET money = money + 1000 WHERE name ='李四';
  • 执行完后查看account表,发现余额没有发生变化,因为此时的事务提交方式为手动提交,需要执行提交操作

  • 提交事务

COMMIT;
  • 提交后发现转账成功

异常事务演示

  • 提交前account表

  • 此时模拟异常事务提交

#查询张三账户余额
SELECT * FROM account WHERE name ='张三';

#将张三账户余额+10000
UPDATE account SET money=money - 10000 WHERE name ='张三';

#模拟异常
INSERT INTO users (username) VALUES ('existing_user');

#将李四账户余额-10000
UPDATE account SET money = money + 10000 WHERE name ='李四';

COMMIT;
  • 提交完后发现有报错,然后查看account,数据没有变化

  • 此时可以执行回滚操作,保证数据库中的正确性和完整性

ROLLBACK;

四、事务操作方式二

  • 开启事务(不设置提交方式为手动的情况下使用)

START TRANSACTION;或BEGIN;
  • 提交事务

COMMIT;
  • 回滚事务

ROLLBACK;

异常事务演示

  • 开启事务

START TRANSACTION;

  • 执行事务操作

#查询张三账户余额
SELECT * FROM account WHERE name ='张三';

#将张三账户余额+10000
UPDATE account SET money=money - 10000 WHERE name ='张三';

#模拟异常
INSERT INTO users (username) VALUES ('existing_user');

#将李四账户余额-10000
UPDATE account SET money = money + 10000 WHERE name ='李四';

  • 如果事务内的操作执行成功,则提交事务

COMMIT;
  • 此时发现出现异常,则回滚操作

ROLLBACK;

五、并发事务问题

  • 在MySQL中,并发事务可能遇到的问题主要包括以下几种:

    • 脏读(Dirty Reads):

      • 一个事务读取了另一个事务未提交的数据。

      • 如果未提交的事务回滚,那么第一个事务读取的数据将是无效的或“脏”的。

    • 不可重复读(Nonrepeatable Reads):

      • 在同一事务内,多次读取同一数据集合时,由于其他事务的更新操作,导致后续读取的数据与之前读取的数据不一致。

    • 幻读(Phantom Reads):

      • 当一个事务重新执行一个查询时,由于另一个事务的插入或删除操作,返回了不同的行集。

      • 例如:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了幻影”。

      • 幻读与不可重复读类似,但通常指的是在范围查询中由于新增或删除行而导致的问题。

六、事务隔离级别

隔离级别

英文名称

脏读

不可重复读

幻读

读未提交

Read Uncommitted

读已提交

Read Committed

可重复读(默认)

Repeatable Read

串行化

Serializable

  • 从上到下,隔离级别越来越高,但是性能越来越差

查看事务隔离级别

SELECT @@TRANSACTION_ISOLATION;

设置事务隔离级别

SET [SESSION/GLOBA] TRANSACTION ISOLATION LEVEL {隔离级别};
  • SESSION:只对当前客户端窗口有效

  • GLOBA:只对所有客户端窗口有效