事务的作用

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  • 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
  • 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行生效,要么全部执行不生效。
  • 事务用来管理 insert,update,delete 语句

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

    事务的基本操作

  • 使用 START TRANSACTIONBEGIN 命令开启一个新的事务。

  • 使用 COMMIT 命令提交事务,使修改永久生效。
  • 使用 ROLLBACK 回滚当前事务,恢复修改的数据。
  • 使用 SET autocommit = [0|1] 禁用或启用当前会话的默认自动提交模式。

默认情况下,MySQL 在启用自动提交模式的情况下运行。这意味着,当不在事务中时,每个语句都是原子的,就好像它被 START TRANSACTIONCOMMIT 包围一样。您不能使用来撤消效果,但是,如果在语句执行期间发生错误,则该语句将回滚。
要对单个语句系列隐式禁用自动提交模式,请使用以下语句:

  1. START TRANSACTION;
  2. UPDATE table2 SET column='xxx' WHERE id=1;
  3. COMMIT;

使用 START TRANSACTION 时,自动提交将保持禁用状态,直到使用 COMMITROLLBACK 结束事务后,自动提交模式将恢复到其以前的状态。
若要显式禁用自动提交模式,请使用以下语句:

  1. SET autocommit=0;

通过将 autocommit 变量设置为 0 来禁用自动提交模式后,对事务安全表(例如 InnoDBNDB 的表)的更改不会立即永久进行。必须使用 COMMIT 将更改存储到磁盘,或者使用 ROLLBACK 忽略更改。
autocommit 是一个会话变量,必须为每个会话设置。要为每个新连接禁用自动提交模式,可以在配置文件中修改。

无法回滚的语句

某些语句无法回滚。通常,这些语句包括数据定义语言(DDL)语句,例如创建或删除数据库的语句,以及创建、删除或更改表结构语句。

设置事务隔离级别

默认的隔离级别是 REPEATABLE-READ 可重复读,级别越高,数据越安全,但性能越低。
image.png
查看当前隔离级别:

  1. show variables like 'transaction_isolation';

设置事务隔离级别语句,仅对当前会话生效:

  1. SET SESSION TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE];

设置事务隔离级别语句,全局生效:

  1. SET GLOBAL TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE];

配置文件中修改,全局生效:

  1. [mysqld]
  2. transaction-isolation = REPEATABLE-READ

脏读

一个事务读取到其他事务没有提交的数据。

模拟

把事务隔离级别设置为 READ UNCOMMITTED

事务1 事务2
begin;
insert into test1 values(1001, ‘name001’);
select * from test1;
查询到 1001 数据
roback;
select * from test1;
查询不到 1001 数据,因为事务1回滚了

不可重复读

一个事务内多次根据同一查询条件查询出来的结果的值不一致。

模拟

把事务隔离级别设置为 READ COMMITTED,准备一条数据 insert into test1 values(1001, 'name001');,再进行测试:

事务1 事务2
begin;
select * from test1;
查询到 name 值为 ‘name001’
update test1 set name=’name001-new’;
select * from test1;
查询到 name 值为 ‘name001-new’
前后两次查询结果不一致,产生了不可重复读问题
commit;

幻读

一个事务内多次根据同一条件查询出来的结果不一致。

模拟

把事务隔离级别设置为 READ COMMITTED,准备一条数据 insert into test1 values(1001, 'name001');,再进行测试:

事务1 事务2
begin;
select * from test1 where id > 0;;
查询到 1 条数据
insert into test1 values(1002, ‘name001’);
select * from test1 where id > 0;;
查询到 2 条数据
前后两次查询结果数量不一致,产生了幻读问题
commit;

参考: https://www.runoob.com/mysql/mysql-transaction.html https://www.cnblogs.com/zhoujinyi/p/3437475.html