Oracle knowledge articles + transaction isolation control

Description: This article is a guidebook for beginners of Oracle transaction isolation control
Tags: Oracle transaction control, transaction isolation, Isolation Level, Transaction Isolation Levels
comparison: This article compares Oracle and MySQL for easy understanding
Note: The unnecessary The redundant part, so that beginners can learn it at a glance
Reminder: If you find something wrong with this article or there is a better way to write it, please leave a message or private message me for modification and optimization


★ Quick overview of conclusions
※ Oracle database provides two international isolation level standards of "Read committed" (default) and "Serializable". In addition, Oracle also provides a non-national standard "read-only" mode
※ MySQL database supports 4 international standards, but the default isolation level is "Repeatable read". In the production environment, it is generally recommended to change to "Read committed" and enable binlog in row format

★ Related Articles
Oracle Official Documents
Why is mysql's default isolation level RR?

★ Knowledge points
※ ISO refers to the International Organization for Standards (International Organization for Standards)
※ ANSI refers to the American National Standards Institute (American National Standards Institute)

★ ANSI/ISO transaction isolation level
The SQL standard adopted by ANSI and ISO/IEC defines four levels of transaction isolation. These levels affect transaction throughput to varying degrees.
These isolation levels are defined in terms of phenomena that must be prevented between concurrently executing transactions. The preventable phenomena are:

※ 脏读(Dirty reads)
	事务读取另一个尚未提交的事务已写入的数据。
※ 不可重复读/模糊读(Nonrepeatable (fuzzy) reads)
	事务重新读取它先前已读取的数据,并发现另一个已提交的事务已修改或删除了该数据。例如,用户查询一行,然后再查询同一行,只是发现数据已更改。
※ 幻读(Phantom reads)
	事务重新运行查询,返回满足搜索条件的一组行,并发现另一个提交的事务已插入满足该条件的其他行。
	例如,某笔交易查询雇员人数。五分钟后,它执行相同的查询,但是现在这个数字增加了一个,因为另一个用户插入了新员工的记录。与以前相比,满足查询条件的数据更多,但是与模糊读取不同,以前读取的数据保持不变。

The SQL standard defines four isolation levels based on the phenomena encountered by transactions that are allowed to run at a particular isolation level.

Preventable read phenomenon by isolation level

isolation dirty read non-repeatable read Phantom reading
Read uncommitted

possible

possible

possible

Read committed

impossible

possible

possible

Repeatable read

impossible

impossible

possible

Serializable

impossible

impossible

impossible


★ Transaction isolation control (Oracle)
※ Oracle's three transaction isolation levels

  1. Read Committed Isolation Level
  2. Serializable Isolation Level
  3. Read-Only Isolation Level

※ Usage case

1. Read Committed Isolation Level

In the default Read Committed isolation level , each query executed by a transaction sees only data that was committed before the query started (not the transaction). This isolation level is suitable for database environments where transactions are rarely likely to conflict.

The following table shows conflicting writes and lost updates in a READ COMMITTED transaction

Session 1 Session 2 Explanation
SQL> SELECT last_name, salary
FROM employees WHERE last_name
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9500
 

Session 1 queries the salaries for Banda, Greene, and Hintz. No employee named Hintz is found.

SQL> UPDATE employees SET salary
= 7000 WHERE last_name = 'Banda';
 

Session 1 begins a transaction by updating the Banda salary. The default isolation level for transaction 1 is READ COMMITTED.

 
SQL> SET TRANSACTION ISOLATION
LEVEL READ COMMITTED;

Session 2 begins transaction 2 and sets the isolation level explicitly to READ COMMITTED.

 
SQL> SELECT last_name, salary
FROM employees WHERE last_name IN
('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9500

Transaction 2 queries the salaries for Banda, Greene, and Hintz. Oracle Database uses read consistency to show the salary for Banda before the uncommitted update made by transaction 1.

 
SQL> UPDATE employees SET salary =
9900 WHERE last_name = 'Greene';

Transaction 2 updates the salary for Greene successfully because transaction 1 locked only the Banda row

SQL> INSERT INTO employees
(employee_id, last_name, email,
hire_date, job_id) VALUES (210,
'Hintz', 'JHINTZ', SYSDATE,
'SH_CLERK');
 

Transaction 1 inserts a row for employee Hintz, but does not commit.

 
SQL> SELECT last_name, salary
FROM employees WHERE last_name IN 
('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9900

Transaction 2 queries the salaries for employees Banda, Greene, and Hintz.

Transaction 2 sees its own update to the salary for Greene. Transaction 2 does not see the uncommitted update to the salary for Banda or the insertion for Hintz made by transaction 1.

 
SQL> UPDATE employees SET salary =
6300 WHERE last_name = 'Banda';

-- prompt does not return 

Transaction 2 attempts to update the row for Banda, which is currently locked by transaction 1, creating a conflicting write. Transaction 2 waits until transaction 1 ends.

SQL> COMMIT;
 

Transaction 1 commits its work, ending the transaction.

 
1 row updated.
 
SQL>

The lock on the Banda row is now released, so transaction 2 proceeds with its update to the salary for Banda.

 
SQL> SELECT last_name, salary
FROM employees WHERE last_name IN
('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6300
Greene              9900
Hintz

Transaction 2 queries the salaries for employees Banda, Greene, and Hintz. The Hintz insert committed by transaction 1 is now visible to transaction 2. Transaction 2 sees its own update to the Banda salary.

 
COMMIT;

Transaction 2 commits its work, ending the transaction.

SQL> SELECT last_name, salary
FROM employees WHERE last_name
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6300
Greene              9900
Hintz
 

Session 1 queries the rows for Banda, Greene, and Hintz. The salary for Banda is 6300, which is the update made by transaction 2. The update of Banda's salary to 7000 made by transaction 1 is now "lost."

序列化读隔离级别中,事务仅看到事务开始时提交的更改(而不是查询)以及事务本身所做的更改。可序列化的事务在使它看起来好像没有其他用户在修改数据库中数据的环境中运行。

2. Serializable Isolation Level

下表显示了可序列化事务如何与其他事务交互。如果可序列化事务在开始可序列化事务之后没有尝试更改另一事务提交的行,那么可以避免序列化访问问题

Session 1 Session 2 Explanation
SQL> SELECT last_name, salary
FROM employees WHERE last_name 
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9500
 

Session 1 queries the salaries for Banda, Greene, and Hintz. No employee named Hintz is found.

SQL> UPDATE employees SET salary
= 7000 WHERE last_name = 'Banda';
 

Session 1 begins transaction 1 by updating the Banda salary. The default isolation level for is READ COMMITTED.

 
SQL> SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE;

Session 2 begins transaction 2 and sets it to the SERIALIZABLE isolation level.

 
SQL> SELECT last_name, salary
FROM employees WHERE last_name 
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9500

Transaction 2 queries the salaries for Banda, Greene, and Hintz. Oracle Database uses read consistency to show the salary for Banda before the uncommitted update made by transaction 1.

 
SQL> UPDATE employees SET salary =
9900 WHERE last_name = 'Greene';

Transaction 2 updates the Greene salary successfully because only the Banda row is locked.

SQL> INSERT INTO employees
(employee_id, last_name, email,
hire_date, job_id) VALUES (210,
'Hintz', 'JHINTZ', SYSDATE,
'SH_CLERK');
 

Transaction 1 inserts a row for employee Hintz.

SQL> COMMIT;
 

Transaction 1 commits its work, ending the transaction.

SQL> SELECT last_name, salary
FROM employees WHERE last_name 
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               7000
Greene              9500
Hintz
SQL> SELECT last_name, salary
FROM employees WHERE last_name IN
('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               6200
Greene              9900

Session 1 queries the salaries for employees Banda, Greene, and Hintz and sees changes committed by transaction 1. Session 1 does not see the uncommitted Greene update made by transaction 2.

Transaction 2 queries the salaries for employees Banda, Greene, and Hintz. Oracle Database read consistency ensures that the Hintz insert and Banda update committed by transaction 1 are not visible to transaction 2. Transaction 2 sees its own update to the Banda salary.

 
COMMIT;

Transaction 2 commits its work, ending the transaction.

SQL> SELECT last_name, salary
FROM employees WHERE last_name
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               7000
Greene              9900
Hintz
SQL> SELECT last_name, salary 
FROM employees WHERE last_name 
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               7000
Greene              9900
Hintz

Both sessions query the salaries for Banda, Greene, and Hintz. Each session sees all committed changes made by transaction 1 and transaction 2.

SQL> UPDATE employees SET salary
= 7100 WHERE last_name = 'Hintz';
 

Session 1 begins transaction 3 by updating the Hintz salary. The default isolation level for transaction 3 is READ COMMITTED.

 
SQL> SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE;

Session 2 begins transaction 4 and sets it to the SERIALIZABLE isolation level.

 
SQL> UPDATE employees SET salary =
7200 WHERE last_name = 'Hintz';

-- prompt does not return

Transaction 4 attempts to update the salary for Hintz, but is blocked because transaction 3 locked the Hintz row. Transaction 4 queues behind transaction 3.

SQL> COMMIT;
 

Transaction 3 commits its update of the Hintz salary, ending the transaction.

 
UPDATE employees SET salary = 7200
WHERE last_name = 'Hintz'
*
ERROR at line 1:
ORA-08177: can't serialize access
for this transaction

The commit that ends transaction 3 causes the Hintz update in transaction 4 to fail with the ORA-08177 error. The problem error occurs because transaction 3 committed the Hintz update after transaction 4 began.

 
SQL> ROLLBACK;

Session 2 rolls back transaction 4, which ends the transaction.

 
SQL> SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE;

Session 2 begins transaction 5 and sets it to the SERIALIZABLE isolation level.

 
SQL> SELECT last_name, salary 
FROM employees WHERE last_name 
IN ('Banda','Greene','Hintz');
 
LAST_NAME         SALARY
------------- ----------
Banda               7100
Greene              9500
Hintz               7100

Transaction 5 queries the salaries for Banda, Greene, and Hintz. The Hintz salary update committed by transaction 3 is visible.

 
SQL> UPDATE employees SET salary =
7200 WHERE last_name = 'Hintz';

1 row updated.

Transaction 5 updates the Hintz salary to a different value. Because the Hintz update made by transaction 3 committed before the start of transaction 5, the serialized access problem is avoided.

Note: If a different transaction updated and committed the Hintz row after transaction transaction 5 began, then the serialized access problem would occur again.

 
SQL> COMMIT;

Session 2 commits the update without any problems, ending the transaction.

只读隔离级别类似于序列化隔离级别,但只读交易不会允许数据在交易中,除非用户进行修改SYS。因此,只读事务不易受该ORA-08177错误的影响。只读事务对于生成报告(其中内容必须与事务开始时间保持一致)很有用。3. Read-Only Isolation Level


★ 事务隔离控制(MySQL)(详情参考引用原文)

在Oracle,SqlServer中都是选择读已提交(Read Commited)作为默认的隔离级别,为什么Mysql不选择读已提交(Read Commited)作为默认隔离级别,而选择可重复读(Repeatable Read)作为默认的隔离级别呢?

这个是有历史原因的,当然要从我们的主从复制开始讲起了!
主从复制,是基于什么复制的?
是基于binlog复制的!这里不想去搬binlog的概念了,就简单理解为binlog是一个记录数据库更改的文件吧~
binlog有几种格式?
OK,三种,分别是

  • statement:记录的是修改SQL语句
  • row:记录的是每行实际数据的变更
  • mixed:statement和row模式的混合

那Mysql在5.0这个版本以前,binlog只支持STATEMENT这种格式!而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的,因此Mysql将可重复读(Repeatable Read)作为默认的隔离级别!

两个疑问

在RC级别下,不可重复读问题需要解决么?
不用解决,这个问题是可以接受的!毕竟你数据都已经提交了,读出来本身就没有太大问题!Oracle的默认隔离级别就是RC,你们改过Oracle的默认隔离级别么?

在RC级别下,主从复制用什么binlog格式?
OK,在该隔离级别下,用的binlog为row格式,是基于行的复制!Innodb的创始人也是建议binlog使用该格式!


※ 如果您觉得文章写的还不错, 别忘了在文末给作者点个赞哦 ~

over

Guess you like

Origin blog.csdn.net/zzt_2009/article/details/114232995