【问题标题】:Idiomatic way to implement atomic web service call [closed]实现原子 Web 服务调用的惯用方式
【发布时间】:2021-06-09 12:58:01
【问题描述】:

我有一个网络服务,它具有创建某种实体的操作。 Web 服务中执行实际工作的方法会调用该 Web 服务的其他几个方法。其中一些方法需要访问数据库才能查询或更新数据。

如何确保作为网络请求的一部分进行的所有调用都是同一事务的一部分?

示例

我的主要方法打开一个数据库连接(和事务)。我应该将数据库连接对象(和/或事务对象)传递给其他方法,以便他们可以重用现有的方法而不是打开自己的方法吗?

我希望尽可能接近这里的标准,但我不确定这种情况,因为您发现的大多数示例只执行单个 SQL,通常在 using 块内。

在我的情况下,我还将使用创建数据库连接的 using 块,并在此块内调用其他几个传递数据库连接的方法。这是好的做法还是有其他方法?

【问题讨论】:

    标签: c# sql web-services transactions


    【解决方案1】:

    如果你有web调用需要在事务中做工作,可以在控制器方法中打开一个TransactionScope,等所有工作完成后调用TransactionScope.Complete(),如下:

    using (var transaction = new TransactionScope())
    {
        // Do the work, no need to pass the transaction anywhere
        WriteSomethingToTheDatabase();
        WriteSomethingElseToTheDatabase();
    
        transaction.Complete();
    }
    
    public void WriteSomethingToTheDatabase()
    {
        // Under the hood, .NET will obtain a connection from the connection pool, and enlist it in the ambient TransactionScope
        using (var connection = new SqlConnection(...))
        {
            // Assuming Dapper for a simpler example. :)
            connection.Execute(...);
        }
    }
    
    public void WriteSomethingElseToTheDatabase()
    {
        // Under the hood, .NET will obtain a connection from the connection pool, and enlist it in the ambient TransactionScope
        using (var connection = new SqlConnection(...))
        {
            // Assuming Dapper for a simpler example. :)
            connection.Execute(...);
        }
    }
    

    如上所述,您不需要在任何地方传递交易,因为它作为“环境”交易工作。也就是说,在此处调用的代码中打开的任何新连接无论如何都会自动“登记”该事务。您应该始终在尽可能短的时间内打开/关闭连接。也不必担心传递连接,因为连接池在后台运行,以确保为您处理实际数据库连接。

    一些注意事项包括:

    • 事务在 Web 服务调用中不起作用(这应该很明显)。因此,如果您在客户端中打开事务,然后通过 HTTP 调用 2 个或更多 Web 服务来执行数据库操作,那么这些 Web 服务进行的任何数据库调用都不会成为客户端事务的一部分。
    • 假设所有涉及的数据库引擎都支持,跨不同类型数据库的事务最终将成为“分布式事务”。 MSSQL、MSMQ、RavenDB 都将加入一个“两阶段提交”事务。理想情况下,您希望避免这种情况,只需让“本地事务”跨连接到单个数据库工作。
    • 请注意,根据您的隔离级别,在不同事务中运行的代码(例如,来自不同用户的另一个 Web 请求进入服务器,在不同线程上执行等)将无法看到更改,直到您提交(通过TransactionScope.Complete())。

    【讨论】:

    • 非常感谢!您的第一个警告是指 Web 服务调用吗?我将尝试为此使用 TransactionScope,它看起来很有希望。当然,这个问题现在因为基于意见而被否决并再次关闭......但这就是完整的 Stackoverflow 体验。
    • 啊,很好看。我已经更正了答案中的第一点。我不确定“基于意见”是否很有帮助,因为所有软件都是基于意见的,并且许多事情确实获得了意见的共识(即出现了一种惯用的做事方式,你问过的任何人都会同意),这应该意味着应该允许使用普遍接受的方法提出这样的问题。但是正如您所说,如果您的问题由于某种愚蠢的原因没有被关闭,那不是 StackOverflow。 ¯_(ツ)_/¯
    • 我现在可以对此进行测试,显然 .NET Core 还不支持它?我正在使用 .NET Core 3.1,我收到消息“此平台不支持分布式事务”,在 Windows 上使用 SQL Server。一旦我使用相同的连接字符串创建第二个 sql 连接,就会出现此错误。
    • 老实说,我不确定它为什么要升级到分布式事务。在比 SQL Server 2000 更新的 SQL Server 上,它会识别到同一个数据库的多个连接,而不是将它们提升为分布式事务。是的,DTC 支持已从 .NET Core 中删除,因为它是跨平台的,并且 DTC 是严格意义上的 Windows 功能。
    • 检查您使用的所有连接字符串是否完全相同,因此使用的连接来自同一个池。除此之外,如果不尝试并自己解决,我不确定。
    猜你喜欢
    • 1970-01-01
    • 2011-01-15
    • 2019-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多