`
liangguanhui
  • 浏览: 111659 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

自斟自饮——2. 简单的并发堵塞回顾

阅读更多



我相信很多朋友对于SQL本身是没什么问题的,但在多用户并发的情况下到底会是如何一个境况,我相信不少人应该还是一头雾水……

(1)在Informix下,
insert into mpolicy select * from mpolicy;

你觉得这条语句的执行结果会使怎么样?如果在mysql(innodb)、oracle、PostgreSQL呢?


(2)在informix下,假设开始的时候,mpolicy没有一个1000 polno的policy,然后开两个dbaccess,然后在第一个执行
begin work;
insert into mpolicy (polno) values (1000);
--记住最后不要commit,也不要关闭窗口,先hold住;



(3)在informix下,假设开始的时候,mpolicy没有一个1000 polno的policy,然后开两个dbaccess,然后在第一个执行
begin work;
insert into mpolicy (polno) values (1000);
--记住最后不要commit,也不要关闭窗口,先hold住;



(4)在informix下,假设开始的时候,mpolicy没有1000和1001 polno的policy,然后开两个dbaccess,然后在第一个执行
begin work;
insert into mpolicy (polno) values (1000);
commit work;  --注意这里提交了一次
begin work;
update mpolicy set polno = 1001 where polno = 1000;
--记住最后不要commit,也不要关闭窗口,先hold住;


然后在第二个里面执行:
begin work;
update mpolicy set polno = 1001 where polno = 1000;
commit work;

你觉得在第二个dbaccess 在执行完begin work之后的剩下两条语句的执行结果会是怎样?第一个dbaccess会有什么相应的变化吗?如果在mysql(innodb)、oracle、PostgreSQL呢?


(5)在informix下,假设开始的时候,mpolicy没有1000和1001 polno的policy,然后开两个dbaccess,然后在第一个执行
begin work;
insert into mpolicy (polno, laname) values (1000, 'ft 0'); 
insert into mpolicy (polno, laname) values (1001, 'ft 1');
commit work;  --注意这里提交了一次
begin work;
update mpolicy set laname = 'ft 1000' where polno = 1000;
--记住最后不要commit,先hold住;


然后在第二个里面执行:
begin work;
update mpolicy set laname = 'ft 2001' where polno = 1001;
--记住最后不要commit,先hold住; 


然后范围刚才第一个dbaccess,继续执行:
update mpolicy set laname = 'ft 1001' where polno = 1001;
--记住最后不要commit,先hold住;


然后又返回第二个里面继续执行:
begin work;
update mpolicy set laname = 'ft 2000' where polno = 1000;


你觉得在第二个dbaccess执行完update之后,结果会是怎样?第一个dbaccess会有什么相应的变化吗?如果在mysql(innodb)、oracle、PostgreSQL呢?





































(1)基本上现代数据库都可以正确执行,执行结果都是把原来的数据copy多一份。但informix的实现机制跟另外三个有点不同。informix的实现是利用临时表作过渡,类似于分两步走,先把mpolicy的数据先插到一个临时表,然后再插回来mpolicy。而其余三个数据库因为有MVCC(Multiple Version Concurrency Control,多版本并发控制),所以不需要临时表作过渡。

另外默认情况下,informix的读写会互相读塞。也就是说,在informix把mpolicy数据插到临时表的过程,其他连接是不能insert或者update这个表的,但可以查询,因为informix会为这个表默认添加一个表级share锁。而把临时表数据插会到mpolicy的时候,会默认添加一个表级exclusive锁,换言之,其他连接不仅不能insert或者update这个表的,查询也不可以。

而Oracle等具备MVCC功能的则不存在这种并发上的限制。
(注意:Oracle从v3就开始支持MVCC,而DB2则是在v9.7才支持,SQL Server在2005才支持,但注意,为了保持先前兼容,DB2和SQLServer的MVCC选项默认是没有打开的。而Informix就不太清楚,好像到v12还没有支持)


(2)正如上面所说,Oracle等因为具备MVCC,所以读写不会互相堵塞,第二个连接的查询不会受到第一个连接的影响。第二个连接的查询结果是no result return.

但informix就不同了,当第一个连接插入polNo= 1000的时候,这一条数据实际上已经加了exclusive锁,于是第二个连接读取这条record的时候就会被堵塞,直到第一个连接commit或者rollback。如果第一个连接commit,那就会返回一条结果;如果第一个连接rollback,那也是no result return.

Informix要实现不堵塞读,只能是set isolation to uncommitted read;如果设置了这一句,查询会立即完成,返回一条数据。(这种情况就是典型的“脏读”,dirty read)


(3)四个数据库的结果都是一样,第二个连接在执行insert完之后立即堵塞,需要等地一个连接的进一步操作。如果第一个连接commit,那就会报错,因为重复主键了;如果第二个连接rollback,那第二个就会插入成功,继续往下面执行。(注意:这个跟MVCC是没有什么关系的)


(4)跟上面一题的情况类似,四个数据库的结果都是一样。


(5)这是一个典型的死锁,基本上现代数据库都可以轻易检测出来。结果会有一个连接报错,另外一个继续下去。上面的情形,通常都是第二个连接报错,第一个继续。
  • 大小: 41.3 KB
3
3
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics