托管ODP.NET调用PUBLIC数据库链接表会导致TNS错误

时间:2016-12-16 20:52:59

标签: oracle odp.net dblink tnsnames odp.net-managed

我们的应用程序使用托管的ODP.NET代码来调用各种Oracle过程。

对于正在使用公共数据库链接并在过程中引用链接表的客户之一,该调用失败。经过进一步测试,任何通过ODP.NET运行查询到链接表的尝试都会失败。

  

ORA-12154:TNS:无法解析指定的连接标识符

完整筹码:

Oracle.ManagedDataAccess.Client.OracleException: ORA-12154: TNS:could not resolve the connect identifier specified 
at OracleInternal.ServiceObjects.OracleCommandImpl.VerifyExecution(OracleConnectionImpl connectionImpl, Int32& cursorId, Boolean bThrowArrayBindRelatedErrors, OracleException& exceptionForArrayBindDML, Boolean& hasMoreRowsInDB, Boolean bFirstIterationDone) 
at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteReader(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, OracleDataReaderImpl& rdrImpl, Int32 longFetchSize, Int64 clientInitialLOBFS, OracleDependencyImpl orclDependencyImpl, Int64[] scnForExecution, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Int64& internalInitialLOBFS, OracleException& exceptionForArrayBindDML, Boolean isDescribeOnly, Boolean isFromEF) 
at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior) at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteDbDataReader(CommandBehavior behavior) 
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
at [APPLICATION CODE]

这很奇怪,因为尝试使用SQL PLUS来生成相同的查询,即使客户端计算机上有没有TNS名称ora文件

我们的应用甚至不使用TNS名称,它使用显式连接字符串详细信息。

我们甚至通过DevArt oracle驱动程序运行测试查询,它们也很成功。

就好像通过托管ODP.NET专门进行调用一样,服务器会以不同的方式处理数据库链接。

ODP.NET  Query (Client Machine A) > (Server A) > Table (Server B) = ERROR
SQL Plus Query (Client Machine A) > (Server A) > Table (Server B) = SUCCESS
DEV ART  Query (Client Machine A) > (Server A) > Table (Server B) = SUCCESS

我们现在使用的测试查询是一个简单的SELECT语句

有没有人知道如何使ODP.NET以与SQL Plus相同的方式为服务器提供服务?

数据库链接信息:

OWNER:    PUBLIC
USERNAME: [FIXED OTHER USER]

3 个答案:

答案 0 :(得分:1)

这肯定是服务器A和服务器B之间的连接(数据库链接)的问题。

服务器A的tnsnames.ora文件中可能缺少服务器B的TNS名称,或者服务器A的数据库链接中的TNS名称可能不正确。

如果这是客户端问题,我可以想象收到ORA-12154错误,但不是ORA-04088:显然,如果你可以进入触发器,你与服务器A的连接是可以的。

我想说下一步是直接连接到服务器A上的数据库,并尝试通过数据库链接查询服务器B上的数据库中的表。我希望这会因为ORA-12154错误而失败。

答案 1 :(得分:0)

根据您的描述,可能是:

  1. 这是您的ODP.NET客户端的配置问题。
  2. 此外,客户端可能不会首先连接到服务器A,更不用说服务器B.
  3. ODP.NET是一个瘦客户端(不涉及本机代码)这一事实应该排除与Oracle Client二进制文件相关的任何配置:驱动程序是“自包含”的,完全独立于SQLplus安装。我的意思是,例如,如果您的计算机的%path%变量中存在错误,则会影响数据的配置,而不会影响所涉及的二进制文件。

    ODP.NET可能看不到合适的ORACLE_HOME变量(例如C:\u01\app\client\product\12.1.0\client_1\)。可能,配置错误表现在ODP.NET无法获取TNS名称文件的位置。

    我建议:

    1. 尝试查看路径中是否首先显示另一个客户端,并隐藏您想要的目录。例如:C:\u01\app\client\product\11.2.1\client_1\bin;C:\u01\app\client\product\12.1.0\client_1\bin。在这种情况下,作为一个快速尝试,首先将您的ODP.NET客户端。这可能会使您的ODP.NET代码获取指向正确Oracle_HOME的指针,并且TNS配置将随之而来。对于复杂的设置,请考虑Oracle在注册表中存储不同的ORACLE_HOME值,并为您提供除%path%中的位置以外的其他方式来选择所需的值。如果感兴趣,请参阅Using Multiple Oracle Homes。当然不要忘记将您的TNS名称放在正确的位置,并且此TNS应指向服务器A,而不是服务器B.
    2. 或者尝试创建一个对正在执行ODP.NET代码的Windows帐户可见的附加环境变量;此变量应调用TNS_ADMIN并指向Oracle客户端的admin目录(类似..product\12.1.0\client_1\network\admin)。确保您的ODP.NET通过从ODP.NET客户端发出string tns_admin = Environment.GetEnvironmentVariable("TNS_ADMIN")来查看它。
    3. 如果上述方法不起作用,请尽量避免使用TNS内容,在连接字符串中指定所有信息,如下所示:
    4. <connectionStrings> <add name="Server_A" connectionString="SERVER=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MyHost)(PORT=MyPort))(CONNECT_DATA=(SERVICE_NAME=MyOracleSID))); uid=myUsername;pwd=myPassword;" /> </connectionStrings>

      后一种设置显示在here或略有不同的替代here

      我认为在您的ODP.NET配置中嵌入TNS信息实际上比依赖主机操作系统配置的任何其他解决方案更清晰,因为使您的ODP.NET真正可移植(部署到TEST或PRODUCTION就是更改ODP.NET配置,而不是主机变量)。有关如何关联TNS和ODP.NET配置的更多示例,请参阅Oracle Managed ODP.NET | Vijay's blog

      最后,SQLPlus工作并不会让人感到意外,因为它可能会看到不同的环境变量来获取连接标识符或ORACLE_HOME。 没有tnsnames.ora文件的事实可能表明

答案 2 :(得分:0)

我们的客户端能够在服务器端修复此问题。问题是DB Link的格式。

原始数据库链接:

CREATE PUBLIC DATABASE LINK [LINK_NAME] 
CONNECT TO [USER] 
IDENTIFIED BY [PASSWORD] 
USING [TNS_NAME]

显然,在ODP.NET上,TNS名称参考不足。一旦客户端切换到完整的连接细节,问题就解决了。

更新了DB Link:

CREATE PUBLIC DATABASE LINK [LINK_NAME] 
CONNECT TO [USER] 
IDENTIFIED BY [PASSWORD]
USING
'(DESCRIPTION = 
     (SDU=[SDU])
     (ADDRESS_LIST = 
          (ADDRESS = (PROTOCOL = TCP)(HOST = [HOSTNAME])(PORT = [PORT]))
     (CONNECT_DATA = (SID=[SID])
)'

此处有更多详情:

https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5005.htm