一个事务与锁的问题

mingleiz 2002-10-10 10:08:52
我在“大本营”中看到一篇“ 也谈SQL SERVER 的锁”的文章(DeD(原作)),有些内容不懂,请各位解释。

我不懂的内容如下:


两个用户同时保存新增的数据,我们的程序开始是这样处理
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锁的连接同时回滚这个事务



请问:为何第二个事务会失败回滚,而不会象第一个事务一样等待,可能我对S、IS、IX等类型的锁理解不够。
...全文
46 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
microlong 2002-10-11
  • 打赏
  • 举报
回复
是不同的连接呀,相同的连接只能等待;不可能IX独占锁在占有资源,现在S共享锁要用!结束独占锁,回滚事务,共享锁的权限不够,同一个连接没有意义呀!
leimin 2002-10-11
  • 打赏
  • 举报
回复
同意CSDNM(CSDN经理(信就不假) 的观点,
microlong 2002-10-11
  • 打赏
  • 举报
回复
实际上楼主的贴的文章中有不正确的地方,SQL SERVER锁机制是有SQL SERVER的是锁管理器来控制,这是个一个运行在后台的智能程序,能根据你的查询自动的来发放行缩,页锁或表锁,实际上如果你的数据量很大如1万行,而你的查询是10行,这时候可能你的系统自动的给分配一个行锁,而不是表锁!
锁的兼容性是不一样的,在两个程序都要对一个数据记录进行更新的时候,那么肯定有一个事务在等待,为什么呢?因为T-SQL,处理数据的机制就是事务,那么这时候就叫阻塞(BLOCKING),如果是事务在同时执行,更改了记录,那么这时候SQL SERVER会结束一个步骤较短的,留下一个较长的事务运行!
如果两个事务都想得到对方的资源,而彼此又不释放自己的资源,那么这时候回形成死锁,SQL 会回滚(ROLLBACK)事务,并返回一个记录错误消息1205!
CSDNM 2002-10-11
  • 打赏
  • 举报
回复
奇怪!

If rs.RecordCount > 0 Then
'表A 的字段A不能从复
cn.RollbackTrans
Else
cn.CommitTrans
End If

能判断重复??
如果重复,在前面cn.Execute "insert into tableA ....."就报主建冲突了!


其实就算是:
cn.BeginTrans
cn.Execute "insert into tableA ....."
If ERR <> 0 Then
cn.RollbackTrans
GOTO THEEND
End If
cn.Execute "insert into tableB ....."
If rs.RecordCount > 0 Then
cn.RollbackTrans
GOTO THEEND
Else
cn.CommitTrans
End If

THEEND:
只要每个用到的地方读是这么些,而不是有些地方写成:
cn.BeginTrans
cn.Execute "insert into tableB ....."
If ERR <> 0 Then
cn.RollbackTrans
GOTO THEEND
End If
cn.Execute "insert into tableA ....."
If rs.RecordCount > 0 Then
cn.RollbackTrans
GOTO THEEND
Else
cn.CommitTrans
End If

就很少死锁!
CSDNM 2002-10-11
  • 打赏
  • 举报
回复
最好能贴全,最后的解决方法?
个人认为,至少这个例子不好,
1、就一条insert语句,可以不必用显式事务。
2、用select count(*) from tableA where ...来检查是否已经插入,也不是正规的用法!

感觉作者对IX锁的理解有些问题,但还没有找到有说服力的资料。
mingleiz 2002-10-11
  • 打赏
  • 举报
回复
今天我查看了一下BOOK ONLINE,但对以上说法还是不能完全理解,能说锝更清楚些吗?(另有高分相送)

34,588

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧