我们的应用程序使用托管的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]
答案 0 :(得分:1)
这肯定是服务器A和服务器B之间的连接(数据库链接)的问题。
服务器A的tnsnames.ora
文件中可能缺少服务器B的TNS名称,或者服务器A的数据库链接中的TNS名称可能不正确。
如果这是客户端问题,我可以想象收到ORA-12154错误,但不是ORA-04088:显然,如果你可以进入触发器,你与服务器A的连接是可以的。
我想说下一步是直接连接到服务器A上的数据库,并尝试通过数据库链接查询服务器B上的数据库中的表。我希望这会因为ORA-12154错误而失败。
答案 1 :(得分:0)
根据您的描述,可能是:
ODP.NET是一个瘦客户端(不涉及本机代码)这一事实应该排除与Oracle Client二进制文件相关的任何配置:驱动程序是“自包含”的,完全独立于SQLplus安装。我的意思是,例如,如果您的计算机的%path%变量中存在错误,则会影响数据的配置,而不会影响所涉及的二进制文件。
ODP.NET可能看不到合适的ORACLE_HOME
变量(例如C:\u01\app\client\product\12.1.0\client_1\
)。可能,配置错误表现在ODP.NET无法获取TNS名称文件的位置。
我建议:
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. TNS_ADMIN
并指向Oracle客户端的admin目录(类似..product\12.1.0\client_1\network\admin
)。确保您的ODP.NET通过从ODP.NET客户端发出string tns_admin = Environment.GetEnvironmentVariable("TNS_ADMIN")
来查看它。 <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>
我认为在您的ODP.NET配置中嵌入TNS信息实际上比依赖主机操作系统配置的任何其他解决方案更清晰,因为使您的ODP.NET真正可移植(部署到TEST或PRODUCTION就是更改ODP.NET配置,而不是主机变量)。有关如何关联TNS和ODP.NET配置的更多示例,请参阅Oracle Managed ODP.NET | Vijay's blog。
最后,SQLPlus工作并不会让人感到意外,因为它可能会看到不同的环境变量来获取连接标识符或ORACLE_HOME
。
没有tnsnames.ora文件的事实可能表明
sqlplus user/password@(description=(address_list=(address=.......ODS)))
(请参阅Ask Tom "How to connect SQLPlus without 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