我创建了将数据插入表格的程序 测试:
CREATE TABLE TEST
(
Id INT,
Name VARCHAR(5)
)
CREATE PROCEDURE usp_insert
(
@i_id INT,
@vc_name VARCHAR(10)
)
AS
BEGIN
BEGIN TRANSACTION
SET NOCOUNT ON ;
BEGIN TRY
DECLARE @new_identity INT;
INSERT INTO dbo.Test
(Id,
name)
VALUES
(@i_id,
@vc_name)
SELECT @new_identity = SCOPE_IDENTITY()
SELECT @new_identity
RETURN(@new_identity)
COMMIT TRANSACTION
COMMIT TRAN
END TRY
BEGIN CATCH
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;
ROLLBACK TRANSACTION
END CATCH
END
插入数据时我收到如下错误
EXEC usp_insert 1,'mohan'
The 'usp_insert' procedure attempted to return a status of NULL, which is not allowed. A status of 0 will be returned instead.
Msg 266, Level 16, State 2, Procedure usp_insert, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
但数据正在插入 和
尝试插入更多长度名称以查看它在数据之前删除的异常,并在第二次尝试时显示异常
EXEC usp_insert 1,'mohankumar'
Msg 266, Level 16, State 2, Procedure usp_insert, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
答案 0 :(得分:2)
致电时
EXEC usp_insert 1,'mohankumar'
' usp_insert'过程尝试返回NULL状态,这是不允许的。将返回状态0。
消息266,级别16,状态2,过程usp_insert,第0行 EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 0,当前计数= 1。
您收到警告,因为您的表格TEST
没有identity
列,因此SELECT @new_identity = SCOPE_IDENTITY()
始终将@new_identity
设置为NULL
,因为@new_identity
返回1}},您从Sql Server收到警告。
您收到事务计数错误,因为控件到达RETURN
语句时存在该过程,并且未执行COMMIT TRANSACTION
。因此,在执行过程之前和之后存在事务计数的不匹配。
您可能认为该过程已保存数据,但事实并非如此,因为事务仍处于打开状态,如果您发出ROLLBACK
,则数据将被回滚。尝试从另一个会话中检查表格中的数据,并在尝试访问该表格时被阻止。
第二次电话
EXEC usp_insert 1,'mohankumar'
消息266,级别16,状态2,过程usp_insert,第0行 EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。先前的计数= 1,当前计数= 0。
上一个事务已经打开,并且由于参数的长度比新行长,因此插入失败,流程将移至catch回滚事务的块。
这是第一次调用usp_insert
时启动的事务,看起来第二次调用删除了上一个插入的数据,但插件从未提交过。
前进之路
SCOPE_IDENTITY()
,您的表格应该有一个IDENTITY
列。如果表中有标识列,那么您不需要将变量传递给标识列的过程RETURN
作为将数据(或插入的id)返回给应用程序的方法。使用SELECT
或OUTPUT
参数。RETURN
应该是BEGIN TRY
中的最后一个语句(除非您有条件检查)。任何COMMIT
/ ROLLBACK
/业务逻辑应该在RETURN
SELECT
返回。 ROLLBACK
您的事务,记录它(如果需要)然后将其丢回应用程序并让应用程序处理错误更新程序
CREATE PROCEDURE usp_insert
(
@i_id INT,
@vc_name VARCHAR(10)
)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
INSERT INTO dbo.Test(Id,name)
VALUES(@i_id,@vc_name)
END TRY
BEGIN CATCH
INSERT Into LogTable
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;
ROLLBACK TRANSACTION;
THROW; -- You can use RAISERROR if your sql server version doesn't support THROW
END CATCH
END
注意:
BEGIN TRAN
和COMMIT
,因为它只是一个DML语句,当前代码不需要显式事务边界。 RETURN
,因为您已经知道要保存的ID。答案 1 :(得分:0)
编写相同功能的更好方法是:
CREATE TABLE TEST
(
Id INT IDENTITY (1,1), -- declare Identity property to auto-increment Id
Name VARCHAR(5)
)
Go
CREATE PROCEDURE usp_insert
@vc_name VARCHAR(10),
@new_identity Int OUTPUT -- Explicitly declare the returned value
AS
BEGIN
BEGIN TRANSACTION
SET NOCOUNT ON ;
BEGIN TRY
INSERT INTO Test
(name)
VALUES
(@vc_name)
SELECT @new_identity = SCOPE_IDENTITY()
SELECT @new_identity
COMMIT TRANSACTION
RETURN(@new_identity)
--COMMIT TRAN -- where is this coming from?
END TRY
BEGIN CATCH
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;
ROLLBACK TRANSACTION
END CATCH
END
GO-- Declare the variable to receive the output value of the procedure.
DECLARE @Id Int;
-- Execute the procedure specifying a name for the input parameter
-- and saving the output value in the variable @Id
EXECUTE usp_insert
'Mohan', @new_identity = @Id OUTPUT;
-- Display the value returned by the procedure.
PRINT 'New Id for this employee is ' +
convert(varchar(10),@Id);
GO