试图在TransactionScope的上下文中打开多个Oracle连接导致ORA-12514

时间:2015-08-27 16:41:41

标签: c# oracle transactions transactionscope distributed-transactions

我正在使用Dapper和Quartz.Net(调度程序)的组合将一个简单对象的信息保存到11gR2数据库(Quartz是自包含的,它自己打开和关闭连接,Dapper调用通过一个程序执行一个过程连接由一个也控制交易的工作单元维护。

我正在使用Microsoft认可的TransactionScope方法来启动事务,并将连接设置为在分布式事务中自动登记(如果已经运行)。 我正在使用12c的Managed Oracle驱动程序,所以没有安装12c客户端。

这是奇怪的。第一个连接总是成功打开并登记到事务中,无论哪个方向我都这样做。 第二个总是失败,并抛出一个ORA-12514错误。

Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-12514: TNS:listener does not currently know of service requested in connect descriptor ---> OracleInternal.Network.NetworkException (0x000030E2): ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
   at OracleInternal.Network.OracleCommunication.DoConnect(String tnsDescriptor)
   at OracleInternal.Network.OracleCommunication.Connect(String tnsDescriptor, Boolean externalAuth, String instanceName)
   at OracleInternal.ServiceObjects.OracleConnectionImpl.Connect(ConnectionString cs, Boolean bOpenEndUserSession, String instanceName)
   at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   at OracleInternal.ConnectionPool.PoolManager`3.GetEnlisted(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp)
   at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword)
   at Oracle.ManagedDataAccess.Client.OracleConnection.Open()

我怀疑这是底层连接的问题,因为如果我删除了事务范围并且只是将两个单独的调用运行保存操作,那么一切正常。 以下是我正在做的事情,裁减和匿名的一个基本例子。

using (var tx = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions {IsolationLevel = isolationLevel})
{
    connection.Open(); // works, BUT if I move this line under the next one, the calendar save will succeed and this will fail.
    quartzScheduler.AddCalendar(calendar.Name, c1, true, true); // calls underlying Quartz class that opens a connection, saves to the db and closes a connection - *** this line will fail ***
    _repository.Save(_connection);
}

MS DTC服务在本地运行(Windows 7),Oracle MTS Recovery服务(适用于11个客户端)已安装并运行。

我阅读了Oracle驱动程序附带的帮助,并按照建议,在项目的x86和x64文件夹中添加了64位和32位驱动程序,并设置为始终作为构建的一部分进行复制;但是我不认为我甚至没有这么做 - 这就像第二次连接总是失败而我无法确定原因。

我的想法已经不多了,一旦你不去保存到一个特定的架构和数据库,这方面的帮助似乎很少。

所有的想法都欢迎,提前感谢!

其他修改

今天早上,我还尝试了一个简单的测试,通过在事务范围内打开两个连接来提升标准事务。 出现同样的问题:

using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted}, EnterpriseServicesInteropOption.Full)) {
   var currentTransaction = Transaction.Current;
   var identifier = currentTransaction.TransactionInformation.DistributedIdentifier;
   using (var oc1 = new CustomOracleConnection(_connectionString, 50, 50)) {
      oc1.Open();
      using (var oc2 = new CustomOracleConnection(_quartzString, 50, 50)) {
         oc2.Open();
      }
   }
}

查看跟踪信息,然后我想知道这是否与池有关。 我尝试在事务范围之外首先打开第二个连接,然后再次尝试。这有效....所以看起来问题是Oracle驱动程序在尝试打开不在池中的第二个连接时有错误?

1 个答案:

答案 0 :(得分:2)

在咨询Oracle之后,我了解到:
a)这是Oracle驱动程序的一个公认的错误,并且已在其代码库中得到修复,但不太可能在第4版中发布,因此可能需要一段时间才能在第5版中看到它。
b)临时解决方法是在连接到数据库时使用SERVICE_NAME而不是SID。

有关详细信息,请参阅Oracle ODP.Net论坛 https://community.oracle.com/message/13275819