我对以下模式的副作用和潜在问题很感兴趣:
CREATE PROCEDURE [Name]
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
[...Perform work, call nested procedures...]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
END
Run Code Online (Sandbox Code Playgroud)
据我所知,当使用单个过程时,此模式是合理的 - 过程将完成所有语句而不会出错,或者它将回滚所有操作并报告错误.
但是,当一个存储过程调用另一个存储过程来执行某个子工作单元时(理解为较小的过程有时会单独调用),我看到与回滚有关的问题 - 一条信息性消息(级别16)发表声明The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION..我假设是因为子过程中的回滚总是回滚最外层事务,而不仅仅是子过程中启动的事务.
我确实希望整个事情回滚并在发生任何错误时中止(并且错误报告给客户端作为SQL错误),我只是不确定外层试图回滚事务的所有副作用已经回滚过了.也许@@TRANCOUNT在每个TRY CATCH层进行回滚之前检查一下?
最后是客户端(Linq2SQL),它有自己的事务层:
try
{
var context = new MyDataContext();
using (var transaction = new TransactionScope())
{
// Some Linq stuff
context.SubmitChanges();
context.MyStoredProcedure();
transactionComplete();
}
}
catch
{
// An …Run Code Online (Sandbox Code Playgroud) 这是我第一次使用交易,我只是想知道我做对了.我应该改变什么吗?我插入帖子(wisp).插入帖子时我需要在commentableEntity表中生成ID并在wisp表中插入该ID.
ALTER PROCEDURE [dbo].[sp_CreateWisp]
@m_UserId uniqueidentifier,
@m_WispTypeId int,
@m_CreatedOnDate datetime,
@m_PrivacyTypeId int,
@m_WispText nvarchar(200)
AS
BEGIN TRANSACTION
DECLARE @wispId int
INSERT INTO dbo.tbl_Wisps
(UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
VALUES
(@m_UserId,@m_WispTypeId,@m_CreatedOnDate,@m_PrivacyTypeId,@m_WispText)
if @@ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error in adding new wisp.', 16, 1)
RETURN
END
SELECT @wispId = SCOPE_IDENTITY()
INSERT INTO dbo.tbl_CommentableEntity
(ItemId)
VALUES
(@wispId)
if @@ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error in adding commentable entity.', 16, 1)
RETURN
END
DECLARE @ceid int
select @ceid = SCOPE_IDENTITY()
UPDATE dbo.tbl_Wisps SET CommentableEntityId = …Run Code Online (Sandbox Code Playgroud)