背景

对于软件开发人员来说,有时候我们需要面对瞬时海量的并发请求,例如阿里双十一等活动,当处理并发流程时需要我们通过各种机制保持数据一致性,其中,最有效的一种机制就是锁机制。而对于数据库管理人员来说,并发问题同样存在。并发问题的本质在于一条逻辑代码在机器层面可能需要几条指令来完成,也就是说这条逻辑代码可能在多个机器周期内完成,如果在顺时执行时这样执行是不会存在问题的,而在并发执行时就会出现数据不一致的情况。这种最小的逻辑指令对应到数据库中就是事务,事务包含原子性(Atomicity)、一致性(Consistency)、一致性(Consistency)和持久性(Durability)。而由于一个事务在机器层面可能需要几条指令完成,这也意味着它在并发时会出现如下问题:脏读、不可重复读和幻读,下面以MySQL为例详细介绍在什么情况下可能会出现上述问题。

Read uncommitted(读未提交)

此事务隔离级别会出现脏读现象*(事务的修改,即使没有提交,其他事务也能看的到),不建议在生产环境中去使用。

实验-> 脏读现象

  • 查看隔离级别

show variables like 'tx_iso%';
  • 修改隔离级别

mysql> set tx_isolation='READ-UNCOMMITTED';

注意:READ-UNCOMMITTED是字符串,如果不使用双引号,就会报错,错误信息如下:

set tx_isolation=READ-UNCOMMITTED;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'READ-UNCOMMITTED' at line 1
  • 创建表

create table test(int id);//典型的错误,可以和java 类比create table test(id int);//正确写法
  • session1中新增一条数据,但是没有提交,可以session2却可以查询到session这条最新数据

脏读、不可重复读和幻读现象

注意:我们需要手动开启事务(begin)和提交事务(commit),不然MySQL会自动提交事务

Read committed(读已提交)

针对当前读,RC隔离级别保证对读取到的记录加锁(记录锁),存在不可重复读现象(在一个事务内,多次读取,会读取到不同的数据)。

实验-> 不可重复读现象

  • 清除test数据

truncate table test;

脏读、不可重复读和幻读现象

我们发现session2中执行两次select * from test会出现不同的结果,这就是不可重复读现象。

Repeatable read(可重复读)

这是MySQL默认隔离级别,解决不可重复读,但是还会出现存在幻读现象。幻读现象就是说当某个会话对某个数据进行修改并提交,而其他会话读取这个数据并不是最新的值。

实验-> 可重复读

session1 session2begin; begin; select ;//获得一个时间点快照,在表记录中的每一个行都会有trx_id,以后每次查询,都会查询比这个trx_id小于等于的值insert;commit; select;

MySQL通过MVCC(解决读写并发问题)和间隙锁(解决写写并发问题)来解决幻读,Repetable Read违反了隔离性,ACID中对隔离性的定义如下:

The isolation property ensures that the concurrent execution of transactions results in a system state that would be obtained if transactions were executed sequentially, i.e., one after the other. Providing isolation is the main goal of concurrency control. Depending on the concurrency control method (i.e., if it uses strict - as opposed to relaxed - serializability), the effects of an incomplete transaction might not even be visible to another transaction

大概意思:一个没有提交的事务对其他事务是不可见的,而提交过的事务对其他事务是可见的。但是Repeatable Read中提交的事务对其他事务是不可见的,显然违反了隔离性。

Serializable(串行化)

串行化解决了脏读、不可重复读、幻读现象,但是效率会比较低下。从MVCC并发控制退化为基于锁的并发控制。不区分快照读与当前读,所有的读操作均为当前读。

相关文章