我对以下模式的副作用和潜在问题很感兴趣:
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) 它们会立即回滚吗?它们会在一段时间后回滚吗?他们是否处于未承诺状态?
如果使用连接池并且只是重置连接,行为是否相同?
在Dan Guzman的博客上阅读这篇文章,我想知道:为什么不是SET XACT_ABORT ON默认行为?是否有一个地方是有害的,或案件多比不太理想/效率SET XACT_ABORT OFF?
假设我有一个发送到我的SQL-Server数据库的查询,它需要超过30秒,并且我的程序抛出SQL Query Timeout异常.查询是否仍然在我的数据库上徘徊,或者一旦抛出异常就会终止它?
根据联机丛书文档SET XACT_ABORT ON,我得到的印象是,如果T-SQL语句引发运行时错误,整个事务将终止并回滚:
备注
当SET XACT_ABORT为ON时,如果Transact-SQL语句引发运行时错误,则终止并回滚整个事务.
在SQL Server 2008 R2中测试:
SET XACT_ABORT ON;
BEGIN TRANSACTION;
PRINT 'TranCount befor an error = '+CAST(@@Trancount AS varchar(50))
DROP TABLE QuertyAsdf
PRINT 'TranCount after an error = '+CAST(@@Trancount AS varchar(50))
Run Code Online (Sandbox Code Playgroud)
给出输出:
TranCount befor an error = 1
Msg 3701, Level 11, State 5, Line 6
Cannot drop the table 'QwertyAsdf', because it does not exist or you do not have permission.
TranCount after an error = 1
Run Code Online (Sandbox Code Playgroud)
如果我使用SqlCommand运行存储过程并且SqlCommand超时,StoredProc会继续执行还是在SqlCommand断开连接时强行退出?
我在MSDN Lbrary中发现和文章解释说try/catch不能处理无法找到对象时抛出的错误.所以,即使我在try/catch中包装一个事务,回滚短语也不会执行:
BEGIN TRY
BEGIN TRANSACTION
SELECT 1 FROM dbo.TableDoesNotExists
PRINT ' Should not see this'
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SELECT
ERROR_MESSAGE()
END CATCH
--PRINT 'Error Number before go: ' + CAST(@@Error AS VARCHAR)
go
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR)
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR)
Run Code Online (Sandbox Code Playgroud)
当对象不存在时,特别是涉及事务时,建议的方法是处理抛出的错误.我应该用这一段代码代替最后两个打印语句:
IF @@ERROR <> 0 AND @@TRANCOUNT > 0
BEGIN
PRINT 'Rolling back txn'
ROLLBACK TRANSACTION
END
go
PRINT 'Transaction Count again: ' …Run Code Online (Sandbox Code Playgroud) 我正在开发游戏数据库。我有一个存储过程,由游戏客户端在传送、登录、注销、死亡等过程中执行。游戏客户端是硬编码的,我无法编辑。
我正在我的程序中做一些事情,例如如果角色登录到游戏,然后将项目添加到角色的库存中。
对于每种不同类型的流程,我都有IF块,并且TRY...CATCH每个“IF”块中都有块,以便能够处理程序中的任何错误。
TRY...CATCH所以,我的问题是,以这种方式使用块确实有意义吗?或者我应该使用SET XACT_ABORT ON声明而不是TRY...CATCH?哪一个更好?顺便说一句,如果IF块中出现任何错误,则该块必须是完整的ROLLBACK。
另外,我的程序是由游戏客户端高度执行的。有近 800 个在线角色一直在游戏中移动并执行我的程序。它应该尽可能快地执行。
ALTER PROCEDURE [dbo].[_AddLogChar]
@CharID INT,
@EventID TINYINT,
@Data1 INT,
@Data2 INT,
@strPos VARCHAR(64),
@Desc VARCHAR(128)
AS
---- !!! KILL PROCEDURE !!! ----
IF (@EventID NOT IN (4,6,20))
BEGIN
RETURN 0;
END
---- BATTLE ARENA | ACADEMY ----
IF (@EventID = 20)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_Battle_Arena
-- Declaration of variables for battle area conditions
DECLARE @CharInBattle VARCHAR(64) …Run Code Online (Sandbox Code Playgroud) sql-server ×6
sql ×5
transactions ×4
c# ×2
linq-to-sql ×1
sqlcommand ×1
t-sql ×1
timeout ×1
try-catch ×1
xact-abort ×1