ms sqlerver 锁实践

来源:互联网 发布:网络基础设施安全 编辑:程序博客网 时间:2024/06/05 05:58

近日在工作中碰到数据并发问题,查了很多资料,网上的内容大同小异,亲身实践了一把,供大家参考:

我的问题是首先要读取数据库里的一行记录,判断其标志,如果没有改过则进行一些业务处理并在最后修改此记录标志为已修改;如果已经改过则直接退出。


实际操作过程中经常会有两个人同时操作,导致重复操作。


解决方法:

把所有操作放在一个事务里,包括一开始的读取标记语句:

begin tran

if exists (select * from table1 where status=0   and id=222 --判断语句

...

update table1 set status=1 where ....

end tran


在判断语句前加行级排它锁,可以防止另一个事务并发读取:

if exists (select * from table1 with(RowLock,XLock) where status=0  and id=222

但据说行级锁占资源多,我测试了一下,如果id上有索引,用EXEC SP_LOCK 查看了一下,锁资源比原来多了5行;如果没有索引,居然多了6000多行!估计是把每一页都加上锁了!于是想了另一个方法,建立一个空表:查询锁表,语句改为针对这个空表作全表锁定

select * from查询锁表 with(tablockx) where 1=0,这样另一个并发事务执行到此即阻塞,直到commit才可执行下去,在事务过程用EXEC SP_LOCK 查看,只比原来多1行。

缺点是只是同时只能允许一个人操作,由于这个操作并不要求实现很高的并发性,所以这个方案应该最合适的了


另外补充的一点:如果在事务中执行了一条update语句,那么其它事务是否能查询这个表呢?这个跟查询的字段是否有索引有关:如果有索引,则可以查询;没有则不能查。大概是没有索引要全表扫描,就和当前事务起了冲突