客户端与服务器端数据库事务

Client-side vs server-side database transactions

SQL Server 中,事务可以在客户端或服务器代码中执行。一位数据库专家曾经告诉我,由于锁定问题,应该避免客户端事务。几年后的现在,我想知道这是否仍然成立。

当然,在某些情况下客户端事务是必需的,但我们假设可以使用客户端或服务器端事务来解决特定问题。

就性能而言,这两种技术中哪一种最好?为什么?

C#(客户端):

using (var transaction = new TransactionScope())
{
    // Insert data into database.

    transaction.Complete();
}

T-SQL(服务器):

CREATE PROCEDURE [dbo].[my_proc]
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @TransactionCount [int]

    BEGIN TRY
        SET @TransactionCount = @@TRANCOUNT

        IF @TransactionCount = 0
            BEGIN TRANSACTION

        -- Insert data

        IF @TransactionCount = 0
            COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0 AND @TransactionCount = 0 
            ROLLBACK TRANSACTION

        ; THROW
    END CATCH
END
GO

服务器端交易更有效率。这样想。如果您在客户端启动事务,那么服务器必须知道事务正在进行中才能提交或回滚。这也导致客户端应用程序和数据库服务器之间的更多通信。

我是客户端事务的大力倡导者,只要它们正确完成即可。

当您执行客户端事务时,您真正要做的就是打开连接并发送 'BEGIN TRAN'。从这里开始,当您围绕不同的 类 传递事务对象并执行更新时,您只是在使用该打开的连接。出于这个原因,我不完全同意 Gregg 的回答,因为您使用的是开放式连接和开放式事务,因此服务器将始终 'know'.

假设它被正确地包围在 Try/Finally 中以关闭它,并且还有一个 'using' 块,它们是非常具体的。在成功使用它们 10 年后,我从未遇到过锁定问题。

我通常使用一个包含多个子 类 的框架...例如,考虑一个 'customer' 对象,其中包含电话号码和地址的集合,每个都有自己的更新每个项目的例程。

如果我要对父级执行更新,将很难使用服务器端事务回滚更改,因为更新都整齐地排列到每个 table/entity 自己的更新存储过程中。

绕过客户端事务并调用此事务中的存储过程让我可以选择在抛出任何异常时完全回滚并在我们知道更新已完成后提交。

如果正确使用客户端事务,它是大人物亲自赠送的礼物。