日期:2014-05-17  浏览次数:20452 次

关于锁的问题?
在修改时用事物处理
begin tran
......
--COMMIT TRAN注释掉不提交
在系统中显示正常,也能继续insert,update操作,
在sql2005中select * from 表 发现表被锁了
select * from 表 with(nolock) 能看到后来插入的数据
当把系统退出重新登录后发现修改的数据和后来输入的数据全没了。
如何解决这种问题?如果不加事物处理是不是不会产生这种问题?
如果表真被锁了如何让insert,update不成功(insert没用事物处理)?

------解决方案--------------------
增删改本身就是隐式事务,当时显式定义是更好。

在没有并发的时候单纯:select * from 表会锁表?你的默认隔离级别是多少?
------解决方案--------------------
在修改时用事物处理
begin tran
......
--COMMIT TRAN注释掉不提交
如果是

begin tran
update other_column=...from table where primaryKey_column=...

就会Key范围的独占锁,针对于page,object级别,各有个意向排他锁。
要是你更新其他行当数据,或者新增行,是不受上面的Key范围锁排斥,即可以进行其他更新插入操作。

当select * from table ,会对表进行一次table scan ,当搜索到前面正在更新的primaryKey_column就会处于等待状态,因为select * from table过程会先是要求page & object级别上的意向共享锁,由于primaryKey_column当前是独占状态,无法释放资源,导致select * from table 一直处于等待状态。

而,select * from 表 with(nolock) 其实就是降低了事务隔离级别,也就是等效于
set transaction isolation level read uncommitted
允许读取未提交的事务。



------解决方案--------------------
可能你用了长连接,后面的插入都被认为是这个事务的,从数据库角度是必须回滚的。

你这个是存储过程BUG引起的,没有讨论价值,检查所有存储过程消除这类错误就是了

唯一可以吸取的就是抛弃长连接,改用短连接,免得一处BUG引起其他问题。

------解决方案--------------------
详细分析:
1、显示事务未提交,数据库采用先写事务日志,后更新到磁盘的方式来处理事务,先修改某一行,数据会锁定该行,并给该行加一个独占锁,这个时候,数据库默认的事务机制是无法读取到这行,导致select * 读取失败,但是查询时加了with(nolock),就会忽视被锁定的行,从而手动提高了并发性。
2、这个时候,insert并不会有问题,因为该锁定是行锁,或者页锁,只要不是架构锁或表锁,insert 都可以。update操作如果不是针对该行操作也可以执行,否则就必须等待这个事务提交并释放该行锁。
3、系统退出后,数据不存在,证明这个事务被回滚,按照第一点的说法,就是数据先写到内存中,但是磁盘上面的数据还是未修改之前的,这个事务因为取消了,导致事务操作失败,数据依然是未修改之前的。

如果不明白,可以看看数据库针对ACID属性的说明。