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

[align=center][img]http://dl.iteye.com/upload/attachment/368520/b4394f4c-14a1-3541-afa0-aee933ab2682.jpg[/img][/align]


我相信很多朋友对于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)这是一个典型的死锁,基本上现代数据库都可以轻易检测出来。结果会有一个连接报错,另外一个继续下去。上面的情形,通常都是第二个连接报错,第一个继续。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值