7

注意请参阅更新 6。它有一个简单的应用程序,演示如何重新创建问题。

我生活在 DTC 的噩梦中……我们的设置是我们有两个数据库;一个 SQL Server 2008 数据库和一个 Oracle 数据库(我相信是 11g)。我已经安装了 oracle MTS 的东西。我已将 DTC 配置为允许分布式事务。所有对 Oracle 表的访问都通过 SQL Server 数据库中的视图进行,这些视图与链接服务器中的 Oracle 表相对。

(关于 DTC 配置:选中-> 网络 DTC 访问、允许远程客户端、允许入站、允许出站、相互验证(尝试了所有 3 个选项)、启用 XA 事务和启用 SNA LU 6.2 事务。DTC 登录NT AUTHORITY\NetworkService

我们的应用程序是一个 ASP.NET MVC 4.0 应用程序,它调用许多 WCF 服务来执行数据库工作。当前,Web 应用程序和 WCF 服务共享同一个应用程序池(不确定是否相关,但以防万一……)

我们的一些服务是交易性的,而另一些则不是。

每个事务性 WCF 服务在其接口上都有以下属性:

[ServiceContract(SessionMode=SessionMode.Required)]

以及接口中方法签名的以下属性:

[TransactionFlow(TransactionFlowOption.Allowed)]

以及每个方法实现的以下属性:

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

在我的数据访问层中,所有事务方法设置如下:

using (IDbConnection conn = DbTools.GetConnection(_configStr, _connStr, true))
{
    using (IDbCommand cmd = DbTools.GetCommand(conn, "SET XACT_ABORT ON"))
    {
        cmd.ExecuteNonQuery();
    }
    using (IDbCommand cmd = DbTools.GetCommand(conn, sql))
    {
       ... Perform actual database work ...
    }
}

事务性服务调用事务性 DAL 代码。想法是将需要事务性(少数情况)的内容与不需要事务性的内容(约 95% 的情况)分开。

不应该存在从事务中调用事务性和非事务性 WCF 方法的情况(尽管我还没有验证这一点,这可能是我的问题的原因。我不确定,这就是我为什么的一部分我在这里问。)

正如我之前提到的,在大多数情况下,这一切都很好。

周期性地,我无法确定是什么启动了它,我开始收到错误。一旦他们开始,几乎所有事情都会在一段时间内开始失败。最终,事情又开始起作用了。不知道为什么......这一切都在一个单一用户的测试环境中。

有时错误是:

无法为链接服务器“ORACLSERVERNAME”的 OLE DB 提供程序“OraOLEDB.Oracle”启动嵌套事务。因为 XACT_ABORT 选项设置为 OFF,所以需要嵌套事务。

这条消息,我猜是当我在事务中有非事务性的东西时发生的,因为我没有XACT_ABORT在非事务性代码中设置(这是完全可行的,如果这能解决我的问题)。

然而,大多数情况下,错误是这样的:

System.Data.SqlClient.SqlException (0x80131904):无法执行操作,因为链接服务器“ORACLSERVERNAME”的 OLE DB 提供程序“OraOLEDB.Oracle”无法开始分布式事务。

现在,最初我们只有在 SQL Server 表上的事务,并且一切正常。直到我们为某些 Oracle 表添加事务支持后,事情才开始失败。我知道 Oracle 事务有效。正如我所说,大多数时候,一切都只是笨拙的多雷,然后有时它开始失败并持续失败一段时间,直到它决定停止失败,然后一切都恢复了。

希望我能弄清楚如何将其作为“功能”出售给我的用户,但我并不乐观,所以我希望能帮助我找到它。如果我遗漏了任何重要信息,请告诉我。

更新 1:我注意到我们的事务似乎没有设置 DistributedIdentifier,所以我添加了EnsureDistributed()这篇博文中的方法:http: //www.make-awesome.com/2010/04/forcibly-creating-a-分布式网络交易/

而不是硬编码的 Guid(这似乎会导致很多问题),我让它为每个事务生成一个新的 Guid,这似乎有效,但它并没有解决我的问题。我想知道缺少 DistribuedIdentifier 是否表明存在其他一些潜在问题。我以前从未处理过这样的环境,所以我不确定什么是“正常”。

更新 2:我注意到 DistributedIdentifier 没有传递给 WCF。从客户端,我在 Transaction.Current.TransactionInformation 中有一个 DistributedIdentifier 和一个 LocalIdentifier。然而,在 WCF 服务器中,只有一个 LocalIdentifier 集,它与客户端的 Guid 不同(这是有道理的,但我希望 DistributedIdentifier 能够通过)。

更新 3:似乎当我处于事务失败中时,即使在我关闭 IIS 之后,我也无法让 DTC 服务关闭并重新启动。例如,如果我进入组件服务并更改安全设置,然后点击“应用”或“确定”,稍等片刻后,我会收到一个对话框,上面写着“无法重新启动 MS DTC 服务。请检查事件日志以获取更多详细信息。”

在事件日志中,我得到了一系列事件:

1 (from MSDTC): "The MS DTC service is stopping"
2 (From MSSQL$SQLEXPRESS): "The connection has been lost with Microsoft Distributed Transaction 
                            Coordinator (MS DTC). Recovery of any in-doubt distributed transactions 
                            involving Microsoft Distributed Transaction Coordinator (MS DTC) 
                            will begin once the connection is re-established. This is an 
                            informational message only. No user action is required."
-- Folowed by these 3 identical messages
3 (from MSDTC Client 2): 'MSDTC encountered an error (HR=0x80000171) while attempting to establish a secure connection with system GCOVA38.'
4 (from MSDTC Client 2): 'MSDTC encountered an error (HR=0x80000171) while attempting to establish a secure connection with system GCOVA38.'
5 (from MSDTC Client 2): 'MSDTC encountered an error (HR=0x80000171) while attempting to establish a secure connection with system GCOVA38.'
6 (From MSDTC 2): MSDTC started with the following settings:
                     Security Configuration (OFF = 0 and ON = 1):
                     Allow Remote Administrator = 0,
                     Network Clients = 1,
                     Trasaction Manager Communication: 
                     Allow Inbound Transactions = 1,
                     Allow Outbound Transactions = 1,
                     Transaction Internet Protocol (TIP) = 0,
                     Enable XA Transactions = 1,
                     Enable SNA LU 6.2 Transactions = 1,
                     MSDTC Communications Security = Mutual Authentication Required,
                     Account = NT AUTHORITY\NetworkService,
                     Firewall Exclusion Detected = 0
                     Transaction Bridge Installed = 0
                     Filtering Duplicate Events = 1

这让我想知道是否有什么东西可能在某处保持交易开放?我的感觉是,由于缺乏更好的术语,“悬空事务”没有被提交或回滚。在我使用 TransactionScope 的每种情况下,它都发生在“使用”语句中,所以一切都应该是回滚或提交。但我真的开始认为,不知何故,有什么东西在泄露……

更新 4:与更新 3 相关。我正在执行手动登记。我们的连接字符串有“Enlist=false”。DBTools.GetConnection()接受一个布尔参数,该参数指定是否将当前事务登记到连接中。我发布此更新是因为,根据更新 3 中的内容,我想知道,也许,不应该征募交易的连接是否以某种方式征募了它们。

public static IDbConnection GetConnection(string configString, string connectionString, bool enlistTransaction)
{
    SqlConnection conn = new SqlConnection(connectionString);
    conn.Open();
    if (enlistTransaction && Transaction.Current != null)
    {
        conn.EnlistTransaction(Transaction.Current);
    }
    return conn;
}

public static IDbCommand GetCommand(IDbConnection conn, string command)
{
    IDbCommand cmd = conn.CreateCommand();
    cmd.CommandText = command;
    return cmd;
}

更新 5:我设法找到了一组单元测试,如果我运行该组,它总是在同一个测试的同一个地方失败(但如果我只是自己运行那个测试,一遍又一遍,它不会'不会失败。它与之前运行的测试有关。)我设法获得了一些 DTC Trace 日志。这是一个显示初始失败事务的日志。我还展示了一些先前的交易,以防看到一些成功的交易有帮助。失败的事务开始于seq=1846

pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.064   ;seq=1822       ;eventid=TRANSACTION_BEGUN                        ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"transaction has begun, description :'<NULL>'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.064   ;seq=1823       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #1. RM guid = '344d3060-811c-4fc6-bab6-0eea76e3af3a'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.064   ;seq=1824       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #2. RM guid = '7b16851c-00a5-41dd-b59c-b003dcae08ec'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.064   ;seq=1825       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1005 enlisted as transaction enlistment #3. RM guid = '72efe9cc-80f2-4a5b-9659-28b07987b600'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.079   ;seq=1826       ;eventid=RECEIVED_COMMIT_REQUEST_FROM_BEGINNER    ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"received request to commit the transaction from beginner"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.079   ;seq=1827       ;eventid=RM_ISSUED_PREPARE                        ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"prepare request issued to resource manager #1004 for transaction enlistment #1"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.079   ;seq=1828       ;eventid=RM_ISSUED_PREPARE                        ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"prepare request issued to resource manager #1004 for transaction enlistment #2"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.079   ;seq=1829       ;eventid=RM_ISSUED_PREPARE                        ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"prepare request issued to resource manager #1005 for transaction enlistment #3"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1830       ;eventid=RM_VOTED_COMMIT                          ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 voted commit for transaction enlistment #2"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1831       ;eventid=RM_VOTED_COMMIT                          ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 voted commit for transaction enlistment #1"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1832       ;eventid=RM_VOTED_READ_ONLY                       ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"resource manager #1005 voted read-only for transaction enlistment #3"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1833       ;eventid=TRANSACTION_COMMITTED                    ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"transaction has got committed"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1834       ;eventid=RM_ISSUED_COMMIT                         ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"commit request issued to resource manager #1004 for transaction enlistment #1"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1835       ;eventid=RM_ISSUED_COMMIT                         ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"commit request issued to resource manager #1004 for transaction enlistment #2"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1836       ;eventid=RM_ACKNOWLEDGED_COMMIT                   ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"received acknowledgement of commit request from the resource manager #1004 for transaction enlistment #1"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.079   ;seq=1837       ;eventid=RM_ACKNOWLEDGED_COMMIT                   ;tx_guid=49a79b73-66c0-48cb-abb1-8b657a2e3e4d     ;"TM Identifier='(null)                                            '" ;"received acknowledgement of commit request from the resource manager #1004 for transaction enlistment #2"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.002   ;seq=1838       ;eventid=TRANSACTION_BEGUN                        ;tx_guid=55dd8607-c01e-4135-a247-7ef435c70bc6     ;"TM Identifier='(null)                                            '" ;"transaction has begun, description :'<NULL>'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.018   ;seq=1839       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=55dd8607-c01e-4135-a247-7ef435c70bc6     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #1. RM guid = '7b16851c-00a5-41dd-b59c-b003dcae08ec'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.018   ;seq=1840       ;eventid=RECEIVED_COMMIT_REQUEST_FROM_BEGINNER    ;tx_guid=55dd8607-c01e-4135-a247-7ef435c70bc6     ;"TM Identifier='(null)                                            '" ;"received request to commit the transaction from beginner"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:45.018   ;seq=1841       ;eventid=TRANSACTION_COMMITTED                    ;tx_guid=55dd8607-c01e-4135-a247-7ef435c70bc6     ;"TM Identifier='(null)                                            '" ;"transaction has got committed"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.106   ;seq=1842       ;eventid=TRANSACTION_BEGUN                        ;tx_guid=cc4a8215-3475-4c14-b40d-d150fc79f8f7     ;"TM Identifier='(null)                                            '" ;"transaction has begun, description :'<NULL>'"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.121   ;seq=1843       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=cc4a8215-3475-4c14-b40d-d150fc79f8f7     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #1. RM guid = '7b16851c-00a5-41dd-b59c-b003dcae08ec'"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.121   ;seq=1844       ;eventid=RECEIVED_COMMIT_REQUEST_FROM_BEGINNER    ;tx_guid=cc4a8215-3475-4c14-b40d-d150fc79f8f7     ;"TM Identifier='(null)                                            '" ;"received request to commit the transaction from beginner"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:45.121   ;seq=1845       ;eventid=TRANSACTION_COMMITTED                    ;tx_guid=cc4a8215-3475-4c14-b40d-d150fc79f8f7     ;"TM Identifier='(null)                                            '" ;"transaction has got committed"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.657   ;seq=1846       ;eventid=TRANSACTION_BEGUN                        ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"transaction has begun, description :'<NULL>'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.657   ;seq=1847       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #1. RM guid = '344d3060-811c-4fc6-bab6-0eea76e3af3a'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1848       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"resource manager #1004 enlisted as transaction enlistment #2. RM guid = '7b16851c-00a5-41dd-b59c-b003dcae08ec'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1849       ;eventid=RM_ENLISTED_IN_TRANSACTION               ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"resource manager #1005 enlisted as transaction enlistment #3. RM guid = '72efe9cc-80f2-4a5b-9659-28b07987b600'"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1850       ;eventid=RECEIVED_ABORT_REQUEST_FROM_NON_BEGINNER ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"received request to abort the transaction from non beginner"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1851       ;eventid=TRANSACTION_ABORTING                     ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"transaction is aborting"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1852       ;eventid=RM_ISSUED_ABORT                          ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"abort request issued to resource manager #1004 for transaction enlistment #1"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1853       ;eventid=RM_ISSUED_ABORT                          ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"abort request issued to resource manager #1004 for transaction enlistment #2"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1854       ;eventid=RM_ISSUED_ABORT                          ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"abort request issued to resource manager #1005 for transaction enlistment #3"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1855       ;eventid=RM_ACKNOWLEDGED_ABORT                    ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"received acknowledgement of abort request from the resource manager #1005 for transaction enlistment #3"
pid=1244       ;tid=6284       ;time=10/15/2013-10:00:59.672   ;seq=1856       ;eventid=RM_ACKNOWLEDGED_ABORT                    ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"received acknowledgement of abort request from the resource manager #1004 for transaction enlistment #2"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:59.672   ;seq=1857       ;eventid=RM_ACKNOWLEDGED_ABORT                    ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"received acknowledgement of abort request from the resource manager #1004 for transaction enlistment #1"
pid=1244       ;tid=8488       ;time=10/15/2013-10:00:59.672   ;seq=1858       ;eventid=TRANSACTION_ABORTED                      ;tx_guid=d07cc436-033c-450b-a36c-7e2fe79cdb81     ;"TM Identifier='(null)                                            '" ;"transaction has been aborted"

我不确定,但可能值得注意的是,在前一个事务的完成和这个事务的开始之间有 14.5 秒的延迟。单元测试似乎挂在那里,我还没有弄清楚为什么。

这可能无关紧要,但失败出现在下面的 ExecuteNonQuery 中:

public IClientInternal GetClient(string clientCode)
{
    string sql = "SELECT [CLIENT_CODE], [COMPANY], [EMPLOYEE] << more fields here >> FROM  OPENQUERY("+
                    _settings.LinkedOracleServer + ", 'SELECT * FROM CLIENT WHERE "+ 
                    "CLIENT_CODE = ''" + clientCode + "'' "+
                    "')";

    using (IDbConnection conn = DbTools.GetConnection(_configStr, _connStr, true))
    {
        using (IDbCommand cmd = DbTools.GetCommand(conn, "SET XACT_ABORT ON"))
        {
            cmd.ExecuteNonQuery();
        }
        using (IDbCommand cmd = DbTools.GetCommand(conn, sql))
        {
            DbTools.AddParameter(cmd, "@CLIENT_CODE", DbType.String, clientCode);
            IDataReader reader = cmd.ExecuteReader();
            if (reader.Read())
            {
                return ClientInternal.FromReaderRecord(reader);
            }
            return null;
        }
    }
}

此代码在最终失败之前被成功调用了多次。

我想知道的是,是否有可能在 Oracle 方面没有正确清除交易。如果我理解正确,Oracle 有 10 个分布式事务限制。它是否可能认为以前的分布式事务仍然处于打开状态(我没有看到任何迹象。所有证据似乎都表明所有以前的事务都在完美运行,并且 DTC 日志显示它们正在提交)。

更新 6:我已经设法用一小段代码解决了这个问题。下面,除了更改 DB 和 clientCode 的名称外,是重现问题的确切代码。我接到一个SqlException电话cmd.ExecuteReader()GetClients() The operation could not be performed because OLE DB provider "OraOLEDB.Oracle" for linked server "ORACLE" was unable to begin a distributed transaction.我可以GetEmployeeBadges()一遍又一遍地打电话,它会起作用的。我可以GetClients()一遍又一遍地打电话,它会起作用的。但是如果我调用 GetEmployeeBadges() 然后在事务中调用GetClients(),它会失败。这似乎是第二次调用在事务中登记的结果。

作为补充说明,GetEmployeeBadges(). 这是我们环境的另一个奇怪之处,但 V_EMPLOYEE 和 V_PAEMPLOYEE 实际上是另一个 Oracle 数据库上的视图。因此,我遇到的 Oracle 服务器在另一台 Oracle 服务器上有视图。所以它是 oracle 表的 oracle 视图的 SQL Server 视图。我知道,这有点疯狂。这里的任何功能都令人惊奇。如果我尝试在事务中运行并GetEmployeeBadges()在事务中登记它,它实际上会失败:Cannot execute the query "<<query text here>>" against OLE DB provider "OraOLEDB.Oracle" for linked server "ORACLE".

我无法想象让这一切变得更简单。

class Program
{
    private static string connStr = @"Server=localhost\SQLEXPRESS;Database=MYDB;Trusted_Connection=True;Enlist=false";
    static void Main(string[] args)
    {
        GetEmployeeBadges();

        using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 15, 0)))
        {
            GetClients();
            ts.Complete();
        }
    }

    private static void GetEmployeeBadges()
    {
        string sql = @"select * from OPENQUERY(ORACLE, 'select a.security_nbr, a.employee, b.last_name, b.first_name, b.department
                        from V_PAEMPLOYEE a, V_EMPLOYEE b
                        where 
                        LENGTH(TRIM(a.SECURITY_NBR)) > 0 and
                        a.EMPLOYEE = b.EMPLOYEE and
                        a.COMPANY = 3')";        
        using (IDbConnection conn = DbTools.GetConnection(connStr))
        {
            using (IDbCommand cmd = DbTools.GetCommand(conn, "SET XACT_ABORT ON"))
            {
                cmd.ExecuteNonQuery();
            }
            using (IDbCommand cmd = DbTools.GetCommand(conn, sql))
            {
                cmd.CommandTimeout = 240;
                IDataReader reader = cmd.ExecuteReader();
            }
        }
    }

    public static void GetClients()
    {
        string clientCode = "clientCode";
        string sql = @"SELECT [CLIENT_CODE], [COMPANY], [EMPLOYEE], [MENU_TOKEN_CODE], [ADMINISTRATOR_FLAG], [SUPERVISOR_FLAG], 
                              [CLIENT_DESCR], [DEFAULT_QUEUE_CODE], [FG_WHSE_CODE], [FRT_WHSE_CODE], [BILL_COMP_CODE], [FI_COMP_CODE], 
                              [DEFAULT_ROLE], [DEFAULT_PRINTER_CODE], [SHIP_PRINTER_CODE], [DEFAULT_DISPLAY] 
                       FROM  OPENQUERY( ORACLE, 'SELECT * FROM CLIENT WHERE CLIENT_CODE = ''clientCode''')";

        using (IDbConnection conn = DbTools.GetConnection(connStr, true))
        {
            using (IDbCommand cmd = DbTools.GetCommand(conn, "SET XACT_ABORT ON"))
            {
                cmd.ExecuteNonQuery();
            }
            using (IDbCommand cmd = DbTools.GetCommand(conn, sql))
            {
                DbTools.AddParameter(cmd, "@CLIENT_CODE", DbType.String, clientCode);
                IDataReader reader = cmd.ExecuteReader();
                reader.Read();
            }
        }
    }
}

DbTools 的东西,如果它有帮助的话是:

public static class DbTools
{
    public static IDbConnection GetConnection(string connectionString)
    {
        return GetConnection(connectionString, false);
    }

    public static IDbConnection GetConnection(string connectionString, bool enlistTransaction)
    {
        SqlConnection conn = new SqlConnection(connectionString);
        conn.Open();
        if (enlistTransaction && Transaction.Current != null)
        {
            conn.EnlistTransaction(Transaction.Current);
        }
        return conn;
    }

    public static IDbCommand GetCommand(IDbConnection conn, string command)
    {
        IDbCommand cmd = conn.CreateCommand();
        cmd.CommandText = command;
        return cmd;
    }

    public static IDbDataParameter AddParameter(IDbCommand cmd, string name, DbType type, object value)
    {
        IDbDataParameter param = cmd.CreateParameter();
        param.ParameterName = name;
        param.DbType = type;
        param.Value = value != null ? value : DBNull.Value;
        cmd.Parameters.Add(param);
        return param;
    }
}

赏金仅剩 23 小时。我很想把这 150 分给某人!!!

4

2 回答 2

0

根据KB187289,Oracle 不支持嵌套事务,因此每当事务在没有干净回滚的情况下中止时出现第一条错误消息。在这种情况下,两个数据库都无法完成事务,并且将停止直到阻塞事务被丢弃。

XACT_ABORT强制事务在第一个运行时错误时终止并立即执行回滚。激活XACT_ABORT所有连接以立即引发运行时错误,其中一个可能导致事务在任一数据库上失败。

如果没有XACT_ABORT,MS SQL 服务器会尝试在嵌套事务中对损坏的查询进行静默的部分回滚。除非明确捕获,否则运行时错误将被抑制并且不会被注意到。

这并不能解决您最初的问题(仍然存在失败的事务),但它使您能够首先看到运行时错误。

TRY...CATCH自 SQL 2005 以来,嵌套事务将是执行正确错误处理的更简洁的方法,但这不是您的选择,因为 Oracle 不支持这些语言扩展。

于 2013-10-14T23:00:35.210 回答
0

问题是由我们非常奇怪的设置引起的。

我们有一个具有链接 Oracle 服务器的 SQL Server。我们在 SQL Server 中为 Oracle 服务器上的表创建视图。Oracle 服务器中有一些视图是另一个 Oracle 服务器中表的视图。我们只是在服务器 2 中的 Oracle 表上的服务器 1 中的 Oracle 视图的 SQL 服务器中创建视图。即使在从视图的视图中获取数据时我们没有使用事务,它也会导致后续执行中的事务失败(如果有人想评论这是怎么可能的,我很想解释一下。)

我们的解决方案是简单地创建第二个链接服务器并绕过视图的视图。您可能想知道为什么我们一开始不这样做,这仅仅是因为在我们遇到这个问题之前,没有令人信服的理由拥有第二个链接服务器(并且第二个服务器上有非常敏感的信息,所以我们有点喜欢最小化访问路径的想法)。显然,我们现在有一个令人信服的理由。

虽然我没有给出 Exth3 的答案,但我确实给了他/她奖励积分,以提供最终导致我发现问题的信息。感谢 Exth3!

于 2013-10-17T12:45:13.840 回答