生命中曾经有过的所有灿烂,原来终究,都需要用寂寞来偿还。
在IT行业,无论是oracle,mysql,还是postgresql数据库,为了保证数据库并发性能和数据一致性,都实现了MVCC功能(多版本并发控制)。用户通过会话访问数据库,内部数据库通过事务来完成用户提交的一项一项请求。
事务中,为了达到AIID属性,数据库中都实现了相应的隔离级别。在SQL标准中,定义了四种隔离级别。
1,read uncommitted(未提交读)
在未提交读级别,事务中的修改,即使没有提交,对其他的事务也都是可以看见的。事务可以读取未提交的数据,
这也被称为脏读(Dirty Read)。这个级别会导致很多问题,所有一般很少使用。
2,read commited(提交读)
大多数数据库系统的默认隔离级别都是read commited。read commited满足前面提到的隔离性的简单定义:一个事务
开始时,只能"看见"已经提交的事务所作的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他
事务都是不可见的。这个级别有时候也可叫做不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果。
3,repeatable read(可重复读)
repeatable read解决了脏读问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可
重复读级别还是无法解决另外一个幻读(phantom read)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录。当之前的事务再次读取该范围的记录时,会产生幻行(phantom row)。
4,serializable(可串行化)
serializable是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读问题。简单来说,serializable会在读取的每一行数据上都加锁。该级别实际中很少使用。
下面使用mysql来实践:
mysql默认的隔离级别为REPEATABLE-READ。
mysql> show variables like '%tx%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
| tx_read_only | OFF |
+---------------+-----------------+
2 rows in set, 1 warning (0.00 sec)
1,修改隔离级别为read uncommitted
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like '%tx%';
+---------------+------------------+
| Variable_name | Value |
+---------------+------------------+
| tx_isolation | READ-UNCOMMITTED |
| tx_read_only | OFF |
+---------------+------------------+
2 rows in set, 1 warning (0.00 sec)
A开启事务,修改数据:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update poor_user set password='123456';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
B事务查看数据
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 123456 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
可以看到,数据没有提交,但是我们可以看到未提交的数据,这就是所谓的脏读,所以在数据库中,该模式是不建议使用的。
2,修改数据库隔离级别为read committed;
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
A事务修改数据
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> update poor_user set password='123456';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
开启B事务查看数据
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 123 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
A事务提交数据,B事务查看数据
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 123456 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
可以看到,B会话中已经看到A提交的数据了。
3,修改数据库隔离级别为repeatable read;
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
A会话开启事务,并修改数据
mysql> start transaction ;
Query OK, 0 rows affected (0.00 sec)
mysql> update poor_user set password='888888';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
开启B会话,查看数据
mysql> start transaction;Query OK, 0 rows affected (0.00 sec)
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 123456 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
B会话中看到数据没变,A中进行数据提交,B中查看:
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 123456 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
可以看到,B事务中还是没看到A中提交的数据。此时,B事务进行提交,查看数据:
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from poor_user;
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| UserID | UserName | Password | UserBirth | Descript |
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
| bbe7faab-7c48-11e9-b4ae-80ce6248ca07 | 唐鹏程,tpc123 | 888888 | 1989-05-13 | 最帅气,最善良,最可爱的男人。|
+--------------------------------------+------------------+----------+------------+-----------------------------------------------+
1 row in set (0.00 sec)
当B事务提交后,他可以看到A事务中提交的数据了。可重复读隔离级别只允许读取已提交记录,而且在一个事务两次读取一个记录期间,其他事务部的更新该记录。
至于可串行化级别,由于在生产环境很少使用,下面只列出它的效果:
serializable完全锁定字段,若一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止。是完整的隔离级别,会锁定对应的数据表格,因而会有效率的问题。
欢迎大家关注以下公众号进行数据库方面知识探讨: