两个用户同时保存新增的数据,我们的程序开始是这样处理 cn.BeginTrans cn.Execute "insert into tableA ....." Set rs = cn.Execute("select count(*) from tableA where ...") If rs.RecordCount > 0 Then '表A 的字段A不能从复 cn.RollbackTrans Else cn.CommitTrans End If
当SQL SERVER 在执行INSERT 命令时如果我们不添加任何参数时 数据库默认申请一个 IX 锁 给表A这时候我们来分析上面的程序,当第一个用户执行 cn.Execute "insert into tableA ....." Connection 向数据库申请了一个 IX 锁 给表A ,与此同时当第二个用户执行 cn.Execute "insert into tableA ....." Connection 也向数据库也成功地申请了一个 IX 锁 给表A ,但是当执行 Set rs = cn.Execute("select count(*) from tableA where ...") 这一句的时候就会有问题产生,我们假设第一个用户先一步执行 ,由于SELECT命令需要向数据库申请一个 S 锁给表A,但是由于这时候表A已经存在一个IX锁并且属于另外一个连接因此他只好在此等候。紧接着第二个 用户也执行 Set rs = cn.Execute("select count(*) from tableA where ...") 他也会向数据库申请一个S 锁给表A ,这时候数据就会自动结束较晚申请IX锁的连接同时回滚这个事务 这样子对于我们的应用来说就是一个很大的失败。
解决的办法一,设置数据参数让我们可以读取没有提交的数据、
cn.BeginTrans cn.Execute "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED " cn.Execute "insert into tableA ....." Set rs = cn.Execute("select count(*) from tableA where ...") If rs.RecordCount > 0 Then '表A 的字段A不能从复 cn.RollbackTrans Else cn.CommitTrans End If cn.Execute "SET TRANSACTION ISOLATION LEVEL READ COMMITTED "
解决的办法二,设置INSERT 命令 参数 with (tablock) 、
cn.BeginTrans cn.Execute "insert into tableA with (tablock) ....." Set rs = cn.Execute("select count(*) from tableA where ...") If rs.RecordCount > 0 Then '表A 的字段A不能从复 cn.RollbackTrans Else cn.CommitTrans End If
解决的办法三,增加一个没有用Lock 表、
cn.BeginTrans cn.Execute "update tmpLockTable set FieldLock=1" cn.Execute "insert into tableA with (tablock) ....." Set rs = cn.Execute("select count(*) from tableA where ...") If rs.RecordCount > 0 Then '表A 的字段A不能从复 cn.RollbackTrans Else cn.CommitTrans End If