存储过程中事务回滚的问题
有两张表,分别为Table1(结构:COLA1 nvarchar(10) null,COLA2 nvarchar(10) null) 和Table2(结构:COLB1 nvarchar(10) not null,COLB2 nvarchar(10) null),向两张表中用INSERT INTO写入数据,用事务处理,如果有一张表写入不成功,则两张表的数据都不写入。
我写了一个存储过程:
[code=SQL][/code]
CREATE PROCEDURE Sp_CU_Test(
@AA1 nvarchar(10),
@AA2 nvarchar(10),
@BB1 nvarchar(10),
@BB2 nvarchar(10)
)
AS
DECLARE @cSqlString1 nvarchar(4000)
DECLARE @cSqlString2 nvarchar(4000)
BEGIN TRAN
SET @cSqlString1 ='INSERT INTO Table1(COLA1,COLA2) VALUES('''+@AA1+''' ,'''+@AA2+''')'
SET @cSqlString2 ='INSERT INTO Table2(COLB1,COLB2) VALUES('''+@BB1+''' ,'''+@BB2+''')'
exec(@cSqlString1+' '+ @cSqlstring2)
if @@ERROR <>0
begin
rollback tran
end
else
commit tran
Go
结果:测试 EXEC Sp_CU_Test 'AA1','AA1',NULL,'BB1'
结果:Table1中写入了记录,Table2中没有写入记录。(要求是如果有一张表写入数据不成功则回滚,而测试结果是Table1写入了记录,Table2没有写入记录)
另外做了一个测试的存储过程:
CREATE PROCEDURE Sp_CU_Test(
@AA1 nvarchar(10),
@AA2 nvarchar(10),
@BB1 nvarchar(10),
@BB2 nvarchar(10)
)
AS
DECLARE @cSqlString1 nvarchar(4000)
DECLARE @cSqlString2 nvarchar(4000)
BEGIN TRAN
--SET @cSqlString1 ='INSERT INTO Table1(COLA1,COLA2) VALUES('''+@AA1+''' ,'''+@AA2+''')'
--SET @cSqlString2 ='INSERT INTO Table2(COLB1,COLB2) VALUES('''+@BB1+''' ,'''+@BB2+''')'
--exec(@cSqlString1+' '+ @cSqlstring2)
INSERT INTO TABLE1(COLA1,COLA2) VALUES(@AA1,@AA2 )
INSERT INTO TABLE2(COLB1,COLB2) VALUES(@BB1,@BB2 )
if @@ERROR <>0
begin
rollback tran
end
else
commit tran
Go
测试结果:EXEC Sp_CU_Test 'AA1','AA2',NULL,'BB1'
在Table1和Table2中都没有写入数据(写Table1的语句可以写入记录,写Table2的语句由于COLB1的值是不允许为NULL,所以不可以写入记录,最后回滚以后,两张表都记录)
问题:1、这两个存储过程看上去差不多,为什么结果会不一样呢?
2、第一个存储过程要怎么样修改才能实现第二个存储过程那样的效果?
------解决方案--------------------动态语句如下实现
SQL code
CREATE PROCEDURE Sp_CU_Test(
@AA1 nvarchar(10),
@AA2 nvarchar(10),
@BB1 nvarchar(10),
@BB2 nvarchar(10)
)
AS
DECLARE @cSqlString1 nvarchar(4000)
DECLARE @cSqlString2 nvarchar(4000)
SET @cSqlString1 ='INSERT INTO Table1(COLA1,COLA2) VALUES('''+@AA1+''' ,'''+@AA2+''')'
SET @cSqlString2 ='INSERT INTO Table2(COLB1,COLB2) VALUES('''+@BB1+''' ,'''+@BB2+''')'
DECLARE @SQL NVARCHAR(400)
SET @SQL = N'
SET XACT_ABORT ON
BEGIN TRAN
' + @cSqlString1 + '
' + @cSqlString2 + '
commit tran
'
exec(@SQL)
Go
------解决方案--------------------
SQL code
SET @cSqlString1 ='INSERT INTO Table1(COLA1,COLA2) VALUES('''+@AA1+''' ,'''+@AA2+''')'
SET @cSqlString2 ='INSERT INTO Table2(COLB1,COLB2) VALUES('''+@BB1+''' ,'''+@BB2+''')'
DECLARE @SQL NVARCHAR(8000)
--2005/2008
BEGIN TRY
BEGIN TRAN
exec(@cSqlString1+' '+ @cSqlstring2)
IF (XACT_STATE()) = 1
COMMIT TRAN
END TRY
BEGIN CATCH
IF (XACT_STATE()) != 1
ROLLBACK TRAN
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
------解决方案--------------------
SQL code
CREATE PROCEDURE Sp_CU_Test
( @AA1 nvarchar(10),
@AA2 nvarchar(10),
@BB1 nvarchar(10),
@BB2 nvarchar(10))
AS
DECLARE @cSqlString1 nvarchar(4000)
DECLARE @cSqlString2 nvarchar(4000)
SET @cSqlString1 ='INSERT INTO Table1(COLA1,COLA2) VALUES('''+@AA1+''' ,'''+@AA2+''')'
SET @cSqlString2 ='INSERT INTO Table2(COLB1,COLB2) VALUES('''+@BB1+''' ,'''+@BB2+''')'
set xact_abort on