关于多个语句一起执行时事务的问题,求原因

mathsfan 2010-10-20 03:26:52
测试1:
declare @t table(a varchar(5))
begin tran

insert @t
select 'd',''

delete 表A

if @@error<>0
rollback tran
else
commit tran
由于:
服务器: 消息 213,级别 16,状态 5,行 4
插入错误: 列名或所提供值的数目与表定义不匹配。
事务正常回滚;
测试2:
declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

delete 表A

if @@error<>0
rollback tran
else
commit tran
由于:
服务器: 消息 8152,级别 16,状态 9,行 4
将截断字符串或二进制数据。
语句已终止。
理论上应该事务会回滚,可是“delete 表A”成功执行掉了,求原因!!!
...全文
156 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
详细看了下XACT_ABORT :
http://technet.microsoft.com/zh-cn/library/ms188792.aspx
终于知道原因了。
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
的确,用了
SET XACT_ABORT ON
就可以了,学习。
billpu 2010-10-20
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 mathsfan 的回复:]

我再试了下:
declare @t table(a varchar(5))
begin tran

insert @t
select 'd',''

delete 表A
print @@error
if @@error<>0
rollback tran
else
commit tran

declare @t table(a varchar(5))
be……
[/Quote]
字段输入不匹配,致命错误,直接退出,自动回滚所有记录
字数长度超出边界还给你一个捕捉到的机会

另外你可以用SET XACT_ABORT 设置为 ON,一个事务出错所有事务回滚,解决你后一个测试的问题
feilniu 2010-10-20
  • 打赏
  • 举报
回复
如18楼所说,这种方法是最方便的:

SET XACT_ABORT ON
declare @t table(a varchar(5))
begin tran
print '1'
insert @t
select 'ddddddd'
print '2'
delete @t
print '3'
commit tran
feilniu 2010-10-20
  • 打赏
  • 举报
回复
LZ的回滚判断有问题。@@error只能判断之前最后一条语句的执行是否出错。

第1种情况没有删除是因为这是名称解析时的错误,语句根本没有进入执行过程。第2种情况是运行时错误,@@error没有判断到,所以删除了。
试试以下代码就清楚了:

--名称解析过程的错误
declare @t table(a varchar(5))
begin tran
print '1'
insert @t
select 'd',''
print '2'
delete @t
print '3'
if @@error<>0
rollback tran
else
commit tran

--运行时错误
declare @t table(a varchar(5))
begin tran
print '1'
insert @t
select 'ddddddd'
print '2'
delete @t
print '3'
if @@error<>0
rollback tran
else
commit tran
中国风 2010-10-20
  • 打赏
  • 举报
回复
declare @t table(a varchar(5))
SET XACT_ABORT ON ;
begin tran

....................SQL
commit tran

--SQL2000最好用以上方法

SQL2005
begin try
begin tran
....SQL
commit tran
end try
begin catch
....
rollback tran
end catch
wujinjian2008n 2010-10-20
  • 打赏
  • 举报
回复
如果是05的话套一个try catch

begin try

end try
begin catch
rollback tran
end catch
louisit 2010-10-20
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 mathsfan 的回复:]
引用 10 楼 louisit 的回复:
SQL code

declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

if @@error<>0
begin
rollback tran
end
else
begin
delete 表A
commit tran
end


……
[/Quote]

呵呵,我是新手,另外问问 sql 事务会自动捕捉错误吗?
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
实际上,我的程序是几个几十个语句放一事务中,其中一个语句报后一个例子的错误,但事务却提交了。而我本意是想回滚的。
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 louisit 的回复:]
SQL code

declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

if @@error<>0
begin
rollback tran
end
else
begin
delete 表A
commit tran
end



这样……
[/Quote]
这种答案就不要回答了,呵呵,因为在实际程序中我是批量提交的大量SQL语句,这只是一个说明问题的例子而已,所以就写了2个语句放在事务中。
louisit 2010-10-20
  • 打赏
  • 举报
回复
请教, sql 事务会自动捕捉吗?
中国风 2010-10-20
  • 打赏
  • 举报
回复
測試1
改動態的方法

declare @t table(a varchar(5))
begin tran

insert @t
EXEC('select ''d''')--如果不能確定列是否存在時
if @@error<>0
BEGIN
rollback TRAN
RETURN
END
SELECT N'已執行1'

EXEC('DELETE A1')--如果表名不存在時

if @@error<>0
BEGIN
rollback TRAN
SELECT N'已執行2'
END
else
commit tran
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
我再试了下:
declare @t table(a varchar(5))
begin tran

insert @t
select 'd',''

delete 表A
print @@error
if @@error<>0
rollback tran
else
commit tran

declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

delete 表A
print @@error
if @@error<>0
rollback tran
else
commit tran
前一种没打印出@@error而后一种打印出@@error了,好像前一种报错以后直接跳出后面其它语句,而后一种却在报错以后继续执行后面的语句,所以后一种@@error为0事务提交,难道跟服务器错误级别或者什么其他东西有关系吗?????求教。
louisit 2010-10-20
  • 打赏
  • 举报
回复

declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

if @@error<>0
begin
rollback tran
end
else
begin
delete 表A
commit tran
end


这样也许就不报错了~
dawugui 2010-10-20
  • 打赏
  • 举报
回复
哦,看错题目了,不好意思.
zsforever 2010-10-20
  • 打赏
  • 举报
回复
换成这样就不删除了
declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'
if @@error<>0
begin
rollback tran
return
end
delete B

if @@error<>0
rollback tran
else
commit tran
中国风 2010-10-20
  • 打赏
  • 举报
回复
樓主要看看孤立事務的處理,不會任何錯誤級別都會返回和提交
測試1改為動態
測試2:
USE tempdb
GO
IF object_id('A') IS NOT NULL
DROP TABLE A
go
CREATE TABLE A(ID int)
INSERT A SELECT 1
go
declare @t table(a varchar(5))
begin tran

insert @t
select 'dsddfsdf'

if @@error<>0
begin
rollback TRAN
RETURN
END
delete A

if @@error<>0
rollback tran
else
commit tran

zsforever 2010-10-20
  • 打赏
  • 举报
回复
insert @t
select 'dsddfsdf'

delete 表A
两个操作,你只判断了最后一个的@@error,第一个是错误码,但你没有处理
mathsfan 2010-10-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 viqn7qdnt 的回复:]
引用 1 楼 dawugui 的回复:
插入错误: 列名或所提供值的数目与表定义不匹配。

将截断字符串或二进制数据。

我觉得提示的很明白了.

插入错误: 列名或所提供值的数目与表定义不匹配。(列名,数量或提供的数据不相符合.)

将截断字符串或二进制数据。(文本型字段,其长度不够)

LZ在问的是事务回滚的问题
[/Quote]
恩,我的重点在于事务回滚的原因...
sql_cctv 2010-10-20
  • 打赏
  • 举报
回复
这样你看下就懂了
加载更多回复(3)

34,576

社区成员

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

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