◎◎◎◎◎◎事务,锁◎◎◎◎◎◎

律己修心 2008-11-04 04:40:26
建立测试环境
create table trantest (a int)
go

create proc p_trantest
as
begin tran
insert into trantest select 1
if @@error<>0 rollback tran
waitfor delay '00:00:30'
insert into trantest select 2
if @@error<>0 rollback tran
commit tran


连接1:
exec p_trantest
--在存储过程为执行结束之前,点查询分析器的取消
--这样,表trantest就被锁住了

连接2:
select * from trantest
--因为被锁住,不会有返回结果


问:
在存储过程中,怎样建立事务,可以应对这种情况:
就算是点查询分析器的取消执行时,事务也一样会回滚,而不必去关闭该连接
难道必须关闭连接吗?原因何在?
谢谢大家
...全文
134 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
律己修心 2008-11-05
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 Garnett_KG 的回复:]
SQL code
create table trantest (a int)
go

create proc p_trantest
as

SET XACT_ABORT ON --打开此选项

begin tran
insert into trantest select 1
if @@error<>0 rollback tran
waitfor delay '00:00:30'
insert into trantest select 2
if @@error<>0 rollback tran
commit tran

[/Quote]

我修改一下

create proc p_trantest
as

SET XACT_ABORT ON --打开此选项

begin tran
insert into trantest select 1
if @@error<>0
begin
print 'failure'--修改后(原存储过程是要求出错之后写日志的)
rollback tran
end
waitfor delay '00:00:30'
insert into trantest select 2
if @@error<>0
begin
print 'failure'
rollback tran
end
commit tran

--Garnett_KG 有没有什么办法解决
这个 点取消时 不回滚事务(关闭连接时,有提交事务的处理提示) 是数据库故意设计的吧,你了解吗?请赐教,不胜感激
CN_SQL 2008-11-05
  • 打赏
  • 举报
回复
[Quote=引用楼主 GDC_ZhaoYZ0304360 的帖子:]
建立测试环境

SQL codecreate table trantest (a int)
go

create proc p_trantest
as
begin tran
insert into trantest select 1
if @@error<>0 rollback tran
waitfor delay '00:00:30'
insert into trantest select 2
if @@error<>0 rollback tran
commit tran



连接1:

SQL codeexec p_trantest
--在存储过程为执行结束之前,点查询分析器的取消
--这样,表trantest就被锁住了


连接2:
select * from trantest
[/Quote]
解决你的这个问题两个方法:
1:存储过程加上set xact_abort on(如果你的需求可以这样的话)
2:select * from trantest with(nolock)(加上NOLOCK,这样查询就不会受影响)
Garnett_KG 2008-11-05
  • 打赏
  • 举报
回复

create table trantest (a int)
go

create proc p_trantest
as

SET XACT_ABORT ON --打开此选项

begin tran
insert into trantest select 1
if @@error<>0 rollback tran
waitfor delay '00:00:30'
insert into trantest select 2
if @@error<>0 rollback tran
commit tran


律己修心 2008-11-05
  • 打赏
  • 举报
回复
顶上去
Garnett_KG 2008-11-05
  • 打赏
  • 举报
回复
1) 查询分析器的"取消"是通过发送ODBC SQLCancel命令做的,Profiler可用Attention事件撲捉到。


2)当点取消时,已经执行完的语句是否要Rollback,是要看xact_abort选项而定的.
EX:

OPEN TRAN

INSERT INTO table....
INSERT INTO table....

UPDATE table... <--- 若此时发生ODBC SQLCancel, 前面的两句Insert是否rollback要看xact_abort选项

3)
[Quote]
但是 加了set xact_abort on 时,出错就直接回滚返回了,根本就不给写错误日志的机会

我是想在存储过程中设置一个事务,出错可以调用其它批处理写错误日志,

在执行过程中点取消时,就全都回滚。
[/Quote]
其实上面都已经有答案了.

[Quote]
解决你的这个问题两个方法:
1:存储过程加上set xact_abort on(如果你的需求可以这样的话)
2:select * from trantest with(nolock)(加上NOLOCK,这样查询就不会受影响)
[/Quote]
[Quote]
一般情况,在程序中执行存储过程是没有地方点击“取消”的,刚才测试了下,点击“取消”可能造成事务挂在那里没有提交和回滚,
那只能说明,我们在点击“取消”后应该执行
if @@TRANCOUNT >0
rollback tran
[/Quote]


Yang_ 2008-11-05
  • 打赏
  • 举报
回复
一般情况,在程序中执行存储过程是没有地方点击“取消”的,刚才测试了下,点击“取消”可能造成事务挂在那里没有提交和回滚,
那只能说明,我们在点击“取消”后应该执行
   if @@TRANCOUNT >0 
rollback tran
Yang_ 2008-11-05
  • 打赏
  • 举报
回复
我的意思是:waitfor delay 是个很特殊的语句,其执行的时候,整个会话处于定制状态,这是只要在事务中,锁肯定没有释放,也就是说,在waitfor delay 执行期间点取消,取消的操作要等waitfor delay完成以后再执行,所以你的测试结果只说明 waitfor delay期间锁未释放,而不能说明 点取消的时候锁未释放


你可以把你的waitfor delay '00:00:30'改成 waitfor delay '00:02:30',而不要点取消,这样在连接二也一样因为锁表而需要等连接一执行完毕

律己修心 2008-11-05
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 Garnett_KG 的回复:]
不知道你要解決什麼.

引用
点取消时 不回滚事务(关闭连接时,有未提交事务的处理提示)是数据库故意设计的吧


是。


另:
关於XACT_ABORT的资料,随机丛书上说的很清楚,你可以去查阅一下。
[/Quote]

--不知道你要解決什麼.
不加set xact_abort on 时 设置的事务,出错时可以用@error<>0来捕捉 从而可以将其写进错误日志

但是 加了set xact_abort on 时,出错就直接回滚返回了,根本就不给写错误日志的机会

我是想在存储过程中设置一个事务,出错可以调用其它批处理写错误日志,

在执行过程中点取消时,就全都回滚。


Garnett_KG 2008-11-05
  • 打赏
  • 举报
回复
不知道你要解決什麼.

[Quote]
点取消时 不回滚事务(关闭连接时,有未提交事务的处理提示)是数据库故意设计的吧
[/Quote]

是。


另:
关於XACT_ABORT的资料,随机丛书上说的很清楚,你可以去查阅一下。
律己修心 2008-11-04
  • 打赏
  • 举报
回复
问题补充:在存储过程执行时 点击取消后 在关闭连接的时候 会提示 “存在未提交的事务,是否提交”的对话框

高手都跑那里去了?
可能是问题的题目有问题啊。
律己修心 2008-11-04
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 hyde100 的回复:]
waitfor delay有什么机制来限定之前的事务取消不了
[/Quote]
貌似没有什么,问题不在这里
律己修心 2008-11-04
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 Yang_ 的回复:]
取消会自动rollback tran

你的测试之所以有问题是因为你使用了waitfor delay,正常情况是没有人会使用这个语句的
[/Quote]

不用waitfor delay也是一样的

这是为了能够有时间点取消

--你的测试之所以有问题是因为你使用了waitfor delay
如果你觉得这个waitfor delay也有问题,请说明一下是什么问题


补充:我提问的目的是想知道如果怎样在存储过程中处理【只要取消就回滚】
hyde100 2008-11-04
  • 打赏
  • 举报
回复
楼主在这种情况下执行一下

rollback tran

强行退出就行了
hyde100 2008-11-04
  • 打赏
  • 举报
回复
waitfor delay有什么机制来限定之前的事务取消不了
Yang_ 2008-11-04
  • 打赏
  • 举报
回复
取消会自动rollback tran

你的测试之所以有问题是因为你使用了waitfor delay,正常情况是没有人会使用这个语句的

律己修心 2008-11-04
  • 打赏
  • 举报
回复
谢谢大家
SF

34,576

社区成员

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

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