MySQL InnoDB 트랜잭션 격리 수준

1. 데이터베이스 트랜잭션 및 격리

데이터베이스 관리 시스템에서 트랜잭션은 논리 또는 작업의 단일 단위이며 때로는 여러 작업으로 구성됩니다. 데이터베이스에서 일관된 모드로 수행 된 논리 계산을 트랜잭션이라고합니다. 한 가지 예는 한 은행 계좌에서 다른 은행 계좌로 이체하는 것입니다. 전체 거래는 한 계좌에서 이체 할 금액을 빼고 동일한 금액을 다른 계좌에 더해야합니다.

데이터베이스 트랜잭션은 정의에 따라  원자 적  (전체가 완료되거나 전혀 영향을 미치지 않아야 함),  일관성  (데이터베이스의 기존 제약 조건을 준수해야 함),  격리  (다른 트랜잭션에 영향을주지 않아야 함) 및  내구성  ( 영구 저장소에 기록되어야 함). [1]  데이터베이스 실무자들은 ACID 라는 약어를 사용하여 데이터베이스 트랜잭션의 이러한 속성을 종종 참조합니다  .

위의 데이터베이스 트랜잭션에 대한 Wikipedia의 설명은 원 자성 (모든 작업 성공 또는 모든 실패), 일관성 (일관성 제약 조건), 격리 (상호 작용 격리) 및 지속성 (성공 / failure는 지속되어야합니다).

이 문서에서는 격리에 대해서만 설명합니다.

트랜잭션 간의 완전한 격리는 데이터베이스 제품의 이상적인 상태입니다. 트랜잭션이 직렬로 실행될 때만 달성 할 수 있습니다. 그러나 대부분의 시스템 읽기 및 쓰기는 28 개 원칙, 쓰기 요청의 20 %, 읽기 요청의 80 %를 준수합니다. 요청이 순차적으로 실행되고 데이터베이스의 성능이 매우 나쁩니다. 성능과 격리를 고려하기 위해 4 개의 격리 수준 (Read Uncommited, Read Commited), Repeatable Read, Serializable, 4 가지 수준의 격리 증가, 동시성 감소, 주류 데이터베이스 제품은 다양한 비즈니스 시나리오에 대해 서로 다른 격리 수준을 사용할 수 있으며, SQL 서버는 기본적으로 RC, MySQL innoDB는 기본적으로 RR을 사용합니다.

다음에서는 MySQL (innoDB 엔진)의 격리 수준과 기본 구현 원칙을 예로 간략하게 설명합니다.

2. 준비

1. 데이터베이스

MySQL 5.7 이상

2. 일반적인 명령

SELECT @@global.tx_isolation;-- 查看全局隔离级别
SELECT @@tx_isolation;-- 查看当前会话数据库隔离级别

SET global transaction isolation level read committed; -- 设置全局隔离级别
SET session transaction isolation level read committed; -- 设置当前会话隔离级别

BEGIN;-- 开启事务
COMMIT;-- 提交事务
ROLLBACK;-- 回滚事务

SET AUTOCOMMIT=0;//关闭事务自动提交
SET AUTOCOMMIT=1;//开启事务自动提交

3. 데이터 초기화

DROP TABLE IF EXISTS `t`;
CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `value` varchar(10) NOT NULL COMMENT 'value',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. 커밋되지 않은 읽기

전역 격리 수준 설정

SET global transaction isolation level read uncommitted;
세션 1 세션 2
BEGIN;  
SELECT * FROM t;  
 

BEGIN;

  INSERT INTO t (id, value) VALUES (1, 'a');
SELECT * FROM t;  
  롤백;
SELECT * FROM t;  
범하다;  

위 표의 동작 과정에 따르면 SESSION1에서 다른 트랜잭션의 미 확약 데이터를 읽을 수 있음을 알 수 있는데,이를 dirty read라고하며 공식 MySQL 해석은 다음과 같다. 

신뢰할 수없는 데이터, 다른 트랜잭션에 의해 업데이트되었지만 아직 커밋 되지 않은 데이터를 검색하는 작업입니다  . 커밋되지 않은 읽기로  알려진  격리 수준 에서만 가능합니다  .

 4. 제출 된 읽기

SET global transaction isolation level read committed;
세션 1 세션 2
BEGIN;  
SELECT * FROM t;  
 

BEGIN;

  INSERT INTO t (id, value) VALUES (1, 'a');
SELECT * FROM t;  
  범하다;
SELECT * FROM t;  
범하다;  

 위 표의 연산 과정에 따르면 SESSION2의 트랜잭션이 커밋되기 전에 SESSION1에서 읽은 데이터는 항상 일관성이 있지만 SESSION1의 트랜잭션에서는 두 번 읽은 데이터가 일관성이 없음을 알 수 있습니다. -반복 가능한 읽기 MySQL의 공식 해석은 다음과 같습니다.

쿼리가 데이터를 검색하고 동일한 트랜잭션 내의 이후 쿼리   가 동일한 데이터를 검색하지만 쿼리가 다른 결과를 반환하는 상황입니다 (그 동안 커밋되는 다른 트랜잭션에 의해 변경됨).

5. 반복 읽기 

SET global transaction isolation level repeatable read;
세션 1 세션 2
BEGIN;  
SELECT * FROM t;  
 

BEGIN;

  INSERT INTO t (id, value) VALUES (1, 'a');
SELECT * FROM t;  
  범하다;
SELECT * FROM t;  
범하다;  

위 표의 작업에 따르면 SESSION1의 트랜잭션에서 언제든지 읽은 데이터는 일관되어 이전의 반복 불가능한 읽기 문제를 피할 수 있으며 두 트랜잭션은 안정된 것으로 보이며 이는 트랜잭션에 대한 우리의 기대를 충족하는 것 같습니다. 특성 (ACID)이지만 실제로 그럴까요?

세션 1 세션 2
BEGIN;  
SELECT * FROM t;  
 

BEGIN;

  INSERT INTO t (id, value) VALUES (1, 'a');
SELECT * FROM t;  
  범하다;
INSERT INTO t (id, value) VALUES (1, 'a');  
SELECT * FROM t;  
범하다;  

두 번째 쿼리 이후에 쓰기 작업을 추가했으며 다음 오류가보고됩니다 (SESSION1의 삽입 문과 SESSION2의 커밋 문의 순서를 조정하면 다음 기사에서 설명 할 다른 효과를 볼 수 있습니다. 잠금)

오류 1062 (23000) : 'PRIMARY'키에 대한 중복 항목 '1' 

질의시 데이터가없고, 쓰기시 기본 키 중복 오류가보고되는데, 이런 현상을 팬텀 읽기라고합니다.

A row that appears in the result set of a query, but not in the result set of an earlier query. For example, if a query is run twice within a transaction, and in the meantime, another transaction commits after inserting a new row or updating a row so that it matches the WHERE clause of the query.

 大意为在一个事务的两次查询之间有另外一个事务提交了新增或修改(包括删除)某一行的操作,这一行匹配当前事务的where条件,就会发生幻读。幻读在select操作下是感知不到的,受益于MySQL的mvcc机制,但严格来说幻读也发生了,什么都没读到,但是在修改的时候发生错误。

6.可串行化

SET global transaction isolation level serializable;
SESSION1 SESSION2
BEGIN;  
SELECT * FROM t;  
 

BEGIN;

  INSERT INTO t(id, value) VALUES(1,'a');
SELECT * FROM t;  
  COMMIT;
SELECT * FROM t;  
COMMIT;  

根据上表中的操作,不同的事务在同时开启的情况下,对一张表的操作读/写并发时会根据先后顺序串行化执行,InnoDB的实现是给所有的select查询添加FOR SHARE MODE,是增加了读意向锁,可以提高读的并发性,这种优化仅在autocommit=0时有效,官方文档:

This level is like REPEATABLE READ, but InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. If autocommit is enabled, the SELECT is its own transaction.

7.总结

 MySQL InnoDB存储引擎提供了四种隔离级别:读未提交(RU) 读已提交(RC) 可重复读(RR) 可串行化(S) 解决的问题以及存在的问题如下表。

  脏读 不可重复读 幻读
读未提交 ✔️ ✔️ ✔️
读已提交 × ✔️ ✔️
可重复读 × × ✔️
可串行化 × × ×

系统可以根据自身对并发性能与数据一致性的容忍程度选择相应的隔离级别,然后通过一定的手段(如加锁)来弥补一致性上的缺失。

 

추천

출처blog.csdn.net/zibaihe007/article/details/111143310