>  기사  >  데이터 베이스  >  MySQL의 트랜잭션, 4가지 주요 기능 및 격리 수준에 대한 심층적인 이해

MySQL의 트랜잭션, 4가지 주요 기능 및 격리 수준에 대한 심층적인 이해

青灯夜游
青灯夜游앞으로
2021-10-12 10:51:201762검색

이 기사는 MySQL의 고급 연구로서 MySQL의 트랜잭션, 4가지 주요 기능(ACID) 및 트랜잭션 격리 수준에 대해 자세히 설명합니다.

MySQL의 트랜잭션, 4가지 주요 기능 및 격리 수준에 대한 심층적인 이해

【관련 권장 사항: mysql 비디오 튜토리얼

이 기사의 작업 및 테스트에 사용된 환경 버전은 5.7.215.7.21

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.21    |
+-----------+
1 row in set (0.00 sec)

记住:我们常见的MySQL存储引擎中只有InnoDB是支持事务的。所以下面的操作也都是在InnoDB下做的。

一. 什么是事务

事务就是现实中抽象出来一种逻辑操作,要么都执行,要么都不执行,不能存在部分执行的情况。

比较经典的案例就是银行转账:小A向小B转账100元

正常的情况:小A的账户扣减100元,小B的账户增加100元。

非正常情况: 小A的账户扣减100元,小B账户金额不变。

非正常情况下,小A账户扣减100之后银行系统出现问题,小B账户增加100元的操作并没有执行。也就是两边金额对不上了,小A不愿意,小B不愿意,银行也不愿意啊。事务的出现就是为了避免非正常情况的出现,让大家都满意。

二. 事务的4大特性(ACID)

1. 原子性(Atomicity)

事务的操作是不可分割的,要么都操作,要么都不操作,就像转账一样,不存在中间状态。而且这个原子性不是说只有一个动作,可能会有很多的操作,但是从结果上看是不可分割的,也就是说原子性是一个结果状态。

2. 一致性(Consistency)

执行事务的前后,数据保持一致,就像银行账户系统一样无论事务是否成功,两者的账户总额应该是一样的。

3. 隔离性(Isolation)

多个事务同时操作数据的时候,多个事务直接互相隔离,不会互相影响。

4. 持久性(Durability)

一个事务在提交后对数据的影响是永久的,写入磁盘中不会丢失。

三. 显式事务、隐式事务

mysql的事务分为显式事务隐式事务,默认的事务是隐式事务,由变量autocommit 在操作的时候会自动开启,提交,回滚。

控制的关键命令如下

set autocommit=0; -- 关闭自动提交事务(显式)
set autocommit=1; -- 开启自动提交事务(隐式)
  -- 当autocommit=0的时候手动控制事务
rollback; -- 回滚事务
commit;  -- 提交事务
-- 当autocommit=1 自动提交事务,但是可以控制手动提交
start transaction; -- 开启事务(或者用begin开启事务)
commit; -- 提交事务
rollback; -- 回滚事务
SAVEPOINT 保存点名称;  -- 保存点(相当于存档,可以不用回滚全部操作)
rollback to  保存点;  -- 回滚到某个保存点 (这个后面就不测试,知道有这个操作就行)

先建一张表ajisun

mysql> create table ajisun(id int(5), name varchar(20) character set utf8  COLLATE utf8_bin ) engine=innodb character set= utf8mb4 COLLATE = utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)

1. 隐式事务

-- 看下当前autocommit的状态是,默认是on状态
mysql> show variables like 'autocommit'; 
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

--  插入一条数据
mysql> insert into ajisun values(1,'阿纪');
Query OK, 1 row affected (0.00 sec)
mysql> rollback;

-- 执行rollback 也是没有效果的,还是能够查询到插入的数据(不需要我们手动控制commit)
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)

2. 显式事务方式1

显式事务由我们自己控制事务的开启,提交,回滚等操作

-- 开启显式事务-回滚
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)

mysql> insert into ajisun values(2,'纪先生');
Query OK, 1 row affected (0.00 sec)
-- 插入后可以看见2条数据
mysql> select * from ajisun;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 阿纪      |
|    2 | 纪先生    |
+------+-----------+
2 rows in set (0.00 sec)
-- 回滚之后上面插入的数据就没了
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
+------+--------+
1 row in set (0.00 sec)
-- 插入一条数据
mysql> insert into ajisun values(2,'ajisun');
Query OK, 1 row affected (0.01 sec)
-- 提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
-- 回滚
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
-- 先提交commit,在rollback 数据依然存在,说明commit生效,事务已提交,回滚就不生效了。
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 阿纪   |
|    2 | ajisun |
+------+--------+
2 rows in set (0.00 sec)

3. 显式事务方式2

使用start transaction

先改成默认的事务 set autocommit=1;

-- 开启事务
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from ajisun where id=1;
Query OK, 1 row affected (0.00 sec)
-- 提交事务
mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    2 | ajisun |
+------+--------+
1 row in set (0.00 sec)
-- 开启事务
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from ajisun where id =2;
Query OK, 1 row affected (0.01 sec)
-- 回滚事务
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
-- 删除操作失效了
mysql> select * from ajisun;
+------+--------+
| id   | name   |
+------+--------+
|    2 | ajisun |
+------+--------+
1 row in set (0.00 sec)

四. 并发事务中的问题

如果对表的操作同一时间只有一个事务就不会有问题,但是这是不可能的。现实中都是尽可能的利用,多个事务同时操作。多个事务就会带来不少的问题,例如脏读脏写`不可重复读幻读

MySQL默认采用的 REPEATABLE_READ 隔离级别 
Oracle默认采用的 READ_COMMITTED 隔离级别

기억하세요:

우리의 공통 MySQL에서는 스토리지 엔진 InnoDB만 트랜잭션을 지원합니다. 따라서 InnoDB에서는 다음과 같은 작업도 수행됩니다.

1. 트랜잭션이란 무엇입니까

트랜잭션은 현실에서 추상화된 논리적 연산입니다. , 모두 실행되거나 아무것도 실행되지 않으며 부분 실행이 있을 수 없습니다.
더 고전적인 사례는 은행 이체입니다. 꼬마 A가 꼬마 B에게 100위안을 이체합니다.

정상 상황: 꼬마 A의 계좌에서 100위안이 차감되고 꼬마 B의 계좌에서 100위안이 늘어납니다.

비정상적인 상황: 꼬마 A의 계좌에서 100위안이 차감되고, 꼬마 B의 계좌에 있는 금액은 변경되지 않습니다.

비정상적인 상황에서 Little A의 계좌에서 100위안이 차감된 후 은행 시스템에 문제가 발생하여 Little B의 계좌에 100위안을 추가하는 작업이 실행되지 않았습니다. 즉, 양쪽의 금액이 일치하지 않습니다. 리틀 A도 의향이 없고, 리틀 B도 의향이 없으며, 은행도 의향이 없습니다. 일의 목적은 비정상적인 상황을 피하고 모두를 만족시키는 것입니다.

2. 4가지 거래의 주요 특징(ACID)

1. )

트랜잭션 작업은 모든 작업이 있든 없든 분할할 수 없습니다. 전송과 마찬가지로 중간 상태가 없습니다. 그리고 이 원자성은 하나의 작업만 있다는 의미가 아니라 여러 작업이 있을 수 있지만 결과와 분리할 수 없으며 이는 원자성이 결과 상태임을 의미합니다.

2. 일관성

거래 성공 여부와 관계없이 거래 실행 전후의 데이터는 일관성을 유지합니다. , 둘 사이의 데이터가 일관되어야 합니다.

3. 격리

여러 트랜잭션이 동시에 데이터를 운영하는 경우 여러 트랜잭션이 서로 직접 격리되어 서로 영향을 미치지 않습니다.

4. 내구성

제출 후 데이터에 대한 트랜잭션의 영향은 영구적이며 디스크에 기록해도 손실되지 않습니다.

🎜🎜3. 명시적 트랜잭션과 암시적 트랜잭션🎜🎜🎜MySQL 트랜잭션은 명시적 트랜잭션암시적 트랜잭션으로 구분됩니다. 에서 기본 트랜잭션은 암시적 트랜잭션이며 autocommit 변수는 작업 중에 자동으로 시작, 커밋 및 롤백됩니다. 🎜🎜제어를 위한 주요 명령어는 다음과 같습니다🎜
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

mysql> show variables like '%transaction_isolation%';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)
🎜먼저 테이블을 생성합니다 ajisun🎜
set global transaction_isolation='read-uncommitted';
set global transaction_isolation='read-committed';
set global transaction_isolation='repeatable-read';
set global transaction_isolation='serializable';
🎜🎜1. 암시적 트랜잭션🎜🎜
mysql> set global transaction_isolation='serializable';
Query OK, 0 rows affected (0.01 sec)
mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)
-- 当前会话(设置之前就已经存在的会,级别是默认的)
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)
🎜🎜2. 명시적 트랜잭션 모드 1🎜🎜🎜트랜잭션 개시를 직접 제어합니다. 커밋, 롤백 및 기타 작업🎜
mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE            |
+-------------------------+
1 row in set (0.00 sec)
set session transaction_isolation='read-uncommitted';
set session transaction_isolation='read-committed';
set session transaction_isolation='repeatable-read';
set session transaction_isolation='serializable';
🎜🎜3. 명시적 트랜잭션 모드 2🎜🎜🎜시작 트랜잭션 사용🎜🎜첫 번째 기본 트랜잭션으로 변경 set autocommit=1;🎜
mysql> set session transaction_isolation='read-uncommitted';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)
🎜🎜4. 동시 트랜잭션 문제🎜🎜🎜테이블에서 동시에 하나의 트랜잭션만 작동하는 경우에는 문제가 없지만 이는 불가능합니다. 실제로는 최대한 활용하며, 동시에 여러 거래가 이루어지기도 한다. 여러 트랜잭션으로 인해 더티 읽기, 더티 쓰기, `반복 불가능한 읽기, 팬텀 읽기와 같은 많은 문제가 발생합니다. >🎜🎜🎜1. 더티 읽기🎜🎜🎜🎜커밋되지 않은 다른 트랜잭션의 수정된 데이터를 읽는 트랜잭션입니다. 🎜🎜🎜예를 들어 두 개의 트랜잭션 a와 b: 동시에 레코드를 운영합니다.🎜🎜트랜잭션 a가 레코드를 수정한 후 아직 데이터베이스에 정식으로 제출되지 않은 상태입니다. 이때 트랜잭션 b는 이를 읽어서 사용합니다. 후속 작업을 위한 읽기 데이터입니다. 🎜🎜트랜잭션 a가 롤백되고 수정된 데이터가 더 이상 존재하지 않으면 트랜잭션 b는 존재하지 않는 데이터를 사용하고 있는 것입니다. 이것은 더러운 데이터입니다. 🎜🎜🎜2. 더티 쓰기(데이터 손실) 🎜🎜🎜🎜A 트랜잭션은 커밋되지 않은 다른 트랜잭션에 의해 수정된 데이터를 수정합니다. 🎜🎜🎜예를 들어 두 트랜잭션 a, b: 동시에 레코드를 작동합니다. 🎜🎜a 트랜잭션은 그렇지 않습니다. 수정 후 변경 제출하면 트랜잭션 b도 동일한 데이터 조각을 수정한 다음 트랜잭션 b가 데이터를 커밋합니다. 🎜🎜트랜잭션 A가 자체 수정 사항을 롤백하고 트랜잭션 b의 수정 사항도 롤백하는 경우 문제는 다음과 같습니다. 트랜잭션 B가 수정되어 제출되었지만 데이터베이스는 변경되지 않았습니다. 이러한 상황을 더티 쓰기라고 합니다. 🎜🎜🎜3. Non-repeatable read🎜🎜🎜🎜A 트랜잭션은 제출된 다른 트랜잭션에 의해 수정된 데이터만 읽을 수 있으며, 다른 트랜잭션이 데이터를 수정하고 제출할 때마다 해당 트랜잭션은 쿼리하여 최신 값을 얻을 수 있습니다. 🎜

也就是在同一个事务中多次读取同一条记录,得到的内容都不一样(在每次读取之前都有其他事务完成修改并提交),这就是不可重复读

4. 幻读

在一个事务内 相同条件查询数据,先后查询到的记录数不一样

也就是一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读

不可重复读和幻读的区别:不可重复读重点在于同一条记录前后数据值不一样(内容的变化),而幻读重点在于相同查询条件前后所获取的记录数不一样(条数的变化)

五. 事务的隔离级别

上面说的事务的并发问题,在不同的场景下要求不一样,能接受的问题也不一样。他们之间的严重性排序如下:

脏写 > 脏读 > 不可重复读 > 幻读

MySQL中提供了4种隔离级别来处理这几个问题,如下

隔离级别 脏读 不可重复读 幻影读
READ- UNCOMMITTED
READ-COMMITTED ×
REPEATABLE-READ × ×
SERIALIZABLE × × ×

SQL 标准定义了四个隔离级别:

  • READ-UNCOMMITTED(读未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读不可重复读幻读。但是并发度最高
  • READ-COMMITTED(读已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,该级别可以防止脏读不可重复读以及幻读。并发度也是最低的
MySQL默认采用的 REPEATABLE_READ 隔离级别 
Oracle默认采用的 READ_COMMITTED 隔离级别

1. 如何设置隔离级别

可以通过变量参数transaction_isolation 查看隔离级别

mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

mysql> show variables like '%transaction_isolation%';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)

修改的命令:SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL $[level];

level的值就是4中隔离级别READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE

设置全局隔离级别

只对执行完该语句之后产生的会话起作用。

当前已经存在的会话无效。

set global transaction_isolation='read-uncommitted';
set global transaction_isolation='read-committed';
set global transaction_isolation='repeatable-read';
set global transaction_isolation='serializable';

例如:

会话A

mysql> set global transaction_isolation='serializable';
Query OK, 0 rows affected (0.01 sec)
mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)
-- 当前会话(设置之前就已经存在的会,级别是默认的)
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

会话B(set之后新建的会话)

mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE            |
+-------------------------+
1 row in set (0.00 sec)

设置会话的隔离级别

对当前会话的所有后续的事务有效

该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务。

如果在事务之间执行,则对后续的事务有效。

set session transaction_isolation='read-uncommitted';
set session transaction_isolation='read-committed';
set session transaction_isolation='repeatable-read';
set session transaction_isolation='serializable';

比如:

会话A

mysql> set session transaction_isolation='read-uncommitted';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)

新建会话B(依然是默认的级别:可重复读)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

2. 怎么选择隔离级别

一般情况下默认的可重复读就好了,一般很少改这个,除非业务场景特殊

记住一点:隔离级别越高,并发问题就越少,但并发性也就越低,所以还是要根据业务选择来。

六. 总结

  • 事务的四大特性:原子性,一致性,隔离性,持久性

  • 事务的常见命令:

    set autocommit=0/1; -- 关闭/开启自动提交事务
    start transaction; -- 开启事务(或者用begin)
    rollback; -- 回滚事务
    commit; -- 提交事务
  • 并发事务的问题:脏写 > 脏读 > 不可重复读 > 幻读

  • 需要熟悉事务的4种隔离级别以及MySQL默认级别

  • 怎么设置隔离级别(global,session)

更多编程相关知识,请访问:编程入门!!

위 내용은 MySQL의 트랜잭션, 4가지 주요 기능 및 격리 수준에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제