在软件使用了SQL Server数据库的场合,运行软件时,出现:
"事务(进程 ID **)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事物"。
分析原因:软件多个进程在调用SQL语句访问数据库表的场合,因为资源互相占用,产生的死锁。
例如:
用户A,访问了表1,同时要更新表2。
用户B,访问了表2,同时要更新表1。
由于用户A访问表1的场合,锁住了表1。用户B访问表2的场合,锁住了表2。用户A等待用户B释放表2。用户B等待用户A释放表1。
又例如:
用户A事务访问了表1,A对表1有共享锁。A在读完表1之后,需要对表1进行修改,即需要由共享锁到独占锁。
而用户B事务对表1享有独占锁。B必须在A释放共享锁之后,才能释放独占锁。然后A必须在B释放独占锁之后才能对表1取得独占锁。
故形成了死锁。
解决方法:主体思想为:避免死锁。
1)避免两个进程同时锁定两个资源。
2)已经同时锁定资源的场合,按照一定的顺序释放资源。
・在select 语句上加上NOLock语句。如:select * from table1 with(NOLock)
解释:加上With(NoLock)后,SELECT不对查询到的资源加锁(或者加Sch-S锁,Sch-S锁可以与任何锁兼容)。因此两个事物可以同时访问同一张表。适合解决:读与写并发死锁的情况。缺点是:导致脏读。
・在select语句之前加上语句:SET TRANSACTION ISOLATION LEVEL。
解释:语句可以读取已由其他事务修改但尚未提交的行。缺点是:导致脏读。
・事务中使用快照隔离。
SET ALLOW_SNAPSHOT_ISOLATION ON
SET READ_COMMITTED_SNAPSHOT ON
解释:使用基于行版本控制的隔离级别(SQL Server 2005支持):开启上面的选项后,SELECT不会对请求的资源加S锁,不加锁或者加Sch-S锁,从而将读与写操作之间发生的死锁几率降至最低;而且不会发生脏读。