- 论坛徽章:
- 3
|
数据库的事务隔离级别有4种:
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
而在PostgreSQL事务隔离级别中,READ UNCOMMITTED是之间被认为是READ COMMITTED,所以实际上只有三种。
PostgreSQL默认隔离级别是READ COMMTIED,而MySQL默认为REPEATABLE READ,另MySQL是有READ UNCOMMITTED这种级别的,不过一般这种事务隔离级别基本上没有什么用。
MySQL 在REPEATABLE READ隔离级别下,普通的select语句是看不到在事务启动之后已经提交的数据,但select for update却能看到,也就是说普通select与select for update看到的结果是不一样的,这是特别需要让开发人员注意的地方。
而PostgreSQL在REPEATABLE READ隔离级别,select for udpate语句和select语句的结果是一样的,都看不到在事务启动之后已经提交的数据。
另MySQL有一个很奇怪的间隙锁,如果表中的数据为(1,2,3,10,11),如果执行select * from t1 where id=6 for update;加锁后,其它的用户将不能插入(4,5,6,7,8,9)的主键值了;如果select for update锁住一个主键值比表中现有主键值还大的一个值时,则此表就不能插入比表中主键值更大的键值了。
下面演示一下:
在PostgreSQL中建测试表和数据:
osdba=# create table t1(id int primary key, info text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
CREATE TABLE
osdba=# insert into t1 values(1,'11111');
INSERT 0 1
osdba=# insert into t1 values(2,'22222');
INSERT 0 1
osdba=# insert into t1 values(3,'33333');
INSERT 0 1
osdba=# insert into t1 values(10,'101010');
INSERT 0 1
osdba=# insert into t1 values(11,'111111');
osdba=# select * from t1;
id | info
----+--------
1 | 11111
2 | 22222
3 | 33333
10 | 101010
11 | 111111
(5 rows)
在MySQL中建测试数据:
mysql> create table t1(id int primary key, info varchar(255));
Query OK, 0 rows affected (0.13 sec)
mysql> insert into t1 values(1,'11111');
Query OK, 1 row affected (0.03 sec)
mysql> insert into t1 values(2,'22222');
Query OK, 1 row affected (0.04 sec)
mysql> insert into t1 values(3,'33333');
Query OK, 1 row affected (0.05 sec)
mysql> insert into t1 values(10,'101010');
Query OK, 1 row affected (0.04 sec)
mysql> select * from t1;
+----+--------+
| id | info |
+----+--------+
| 1 | 11111 |
| 2 | 22222 |
| 3 | 33333 |
| 10 | 101010 |
| 11 | 111111 |
+----+--------+
5 rows in set (0.00 sec)
先测试PostgreSQL:
在窗口1中,在“REPEATABLE READ”启动一个事务:
osdba=# begin isolation level REPEATABLE READ ;
BEGIN
在窗口2中,往表插入一条记录:
osdba=# insert into t1 values(5,'555555');
INSERT 0 1
然后再回到窗口1中:
osdba=# select * from t1 where id=5;
id | info
----+------
(0 rows)
osdba=# select * from t1 where id=5 for update;
id | info
----+------
(0 rows)
可以看到在PostgreSQL中不管是select语句不管加不加for update,看到的结果都是一样的,都看不到id=5记录。
而MySQL是不一样的,MySQL的普通select 语句是看不到id=5的记录,但select for update却能看到,见下面:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where id=5;
Empty set (0.00 sec)
mysql> select * from t1 where id=5 for update;
+----+-------+
| id | info |
+----+-------+
| 5 | 55555 |
+----+-------+
1 row in set (0.00 sec)
mysql>
可以看到MySQL在REPEATABLE READ隔的级别下,看到的select for update与普通的select 看到的结果是不一样的。
在MySQL中,一旦设置了SERIALIZABLE级别后,在事务中一旦查询表,就会把查询的记录都锁住,而PostgreSQL中的SERIALIZABLE也与MySQL中完全不一样。查询不会锁表。
在PostgreSQL中,在窗口1中先开始一个事务,然后在窗口2中再开始一个事务,窗口2中修改id=3的记录,再到窗口1中修改id=3的记录时,会报错,由此实现了SERIALIZABLE的隔离级别。
由此可见在SERIALIZABLE的级别上,PostGreSQL的并发会比MySQL好很多。 |
|