托管ODP.NET呼叫对公共数据库链接表引起了TNS错误



我们的应用程序使用托管的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]

这很奇怪,因为即使在客户端计算机上没有没有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

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

有人知道我们如何像SQL Plus一样将ODP.NET推迟到服务器以获取此信息?

db链接信息:

OWNER:    PUBLIC
USERNAME: [FIXED OTHER USER]

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

tnsnames.ora文件中,服务器B中的TNS名称可能丢失了服务器A或服务器A在其数据库链接中具有错误的TNS名称。

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

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

从您的描述中,可能是:

  1. 这是您的ODP.NET客户端的配置问题。
  2. 此外,客户端可能首先无法连接到服务器A,更不用说服务器b。

ODP.NET是一个薄的客户端(不涉及本机代码)的事实,应排除与Oracle客户端二进制文件相关的任何配置:驱动程序是"自我包含"的,并且完全独立于您的SQLPLUS安装。我的意思是,例如,如果计算机的%路径%变量存在错误,它会影响数据的配置,而不是所涉及的二进制文件。

可能是ODP.NET可能看不到适当的ORACLE_HOME变量(例如C:u01appclientproduct12.1.0client_1)。而且可能,配置错误在ODP.NET无法获取TNS名称文件的位置中表现出来。

我建议:

  1. 尝试查看是否有另一个客户出现在您的路径中,并隐藏您的预期目录。例如:C:u01appclientproduct11.2.1client_1bin;C:u01appclientproduct12.1.0client_1bin。在这种情况下,作为快速尝试,请将您的ODP.NET客户端放在首位。这很可能会使您的ODP.NET代码拾取指向正确的Oracle_home的指针,并且将随后进行TNS配置。对于复杂的设置,请考虑Oracle将不同的ORACLE_HOME值存储在注册表中,并为您提供其他方式以外的位置,以选择所需的位置。如果有兴趣,请参见使用多个Oracle Homes。当然,不要忘记将您的TNS名称放在正确的位置,该TNS应该指向服务器A,而不是服务器b。
  2. 另外,尝试创建一个可见的Windows帐户可见的其他环境变量,该变量正在执行ODP.NET代码;该变量应称为TNS_ADMIN,并指向Oracle客户端的管理目录(类似于..product12.1.0client_1networkadmin)。确保您的ODP.NET通过从ODP.NET客户端发出string tns_admin = Environment.GetEnvironmentVariable("TNS_ADMIN")来看到它。
  3. 如果以上不起作用,请尝试完全避免使用TNS的内容,以这样的连接字符串中指定所有信息:

<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>

后一个设置在此处显示或此处略有不同的替代方案。

我认为,将TNS信息嵌入您的ODP.NET配置实际上比依赖主机OS配置的任何其他解决方案都要干净,因为使您的ODP.NET真正便携ODP.NET配置,而不是主机变量)。有关如何关联TNS和ODP.NET配置的更多示例Vijay的博客。

最后,SQLPlus正在工作并不令人惊讶,因为它可能看到不同的环境变量以获取连接标识符或ORACLE_HOME
完全没有tnsnames.ora文件的事实可能表明

  • 运行的任何一个sqlpus都在命令行上指定连接,例如sqlplus user/password@(description=(address_list=(address=.......ODS)))(请参阅TOM"如何在没有TNSNAMES.ora的情况下连接sqlplus")
  • 或Oracle实例位于同一服务器上,因此严格不需要侦听器,您可以跳过TNS配置(请参阅需要侦听器的连接)

我们的客户端能够在服务器端解决此问题。问题是DB链接的格式。

原始DB链接:

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

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

更新的DB链接:

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

最新更新