con - python oracle 12c
cx_Oracle no se conecta al usar SID en lugar del nombre del servicio en la cadena de conexión (6)
Tengo una cadena de conexión que se parece a esto
con_str = "myuser/[email protected]:1521/ora1"
Donde ora1
es el SID de mi base de datos. Usar esta información en SQL Developer funciona bien, lo que significa que puedo conectarme y consultar sin problemas.
Sin embargo, si intento conectarme a Oracle utilizando esta cadena, falla.
cx_Oracle.connect(con_str)
DatabaseError: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
Este formato de cadena de conexión funciona si el ora1
es un nombre de servicio, sin embargo.
He visto otras preguntas que parecen tener el reverso de mi problema (funciona con SID, pero no con el nombre de servicio)
- Usar los nombres de servicio de Oracle con SQLAlachemy
- Nombre de Oracle SID y servicio; problemas de conexión
- cx_Oracle y conexión a Oracle DB de forma remota
¿Cuál es la forma correcta de conectarse a Oracle utilizando cx_Oracle
, utilizando un SID
y no un nombre de servicio? ¿Cómo hago esto sin la necesidad de ajustar el archivo TNSNAMES.ORA
? Mi aplicación se distribuye a muchos usuarios internamente y hacer cambios en el archivo TNSNAMES
es menos que ideal cuando se trata de usuarios sin privilegios de administrador en sus máquinas con Windows. Además, cuando uso el nombre del servicio, no necesito tocar este archivo y me gustaría que lo mantuviera de esa manera.
En una situación similar, pude conectarme a la base de datos usando cx_Oracle.makedsn()
para crear una cadena dsn con un SID
dado (en lugar del nombre del servicio):
dsnStr = cx_Oracle.makedsn("oracle.sub.example.com", "1521", "ora1")
Esto devuelve algo así como
(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle.sub.example.com)(PORT=1521)))(CONNECT_DATA=(SID=ora1)))
que luego se puede usar con cx_Oracle.makedsn() para conectarse a la base de datos:
con = cx_Oracle.connect(user="myuser", password="mypass", dsn=dsnStr)
print con.version
con.close()
Es posible que los SID no sean de fácil acceso o que no los haya creado para su base de datos.
En mi caso, estoy trabajando desde el lado del cliente solicitando acceso a una base de datos en la nube, por lo que crear un SID no tiene sentido.
En su lugar, es posible que tenga una cadena que se parece a esto:
"(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = something.cloud.company)
(PORT = 12345)) (ADDRESS = (PROTOCOL = TCP)(HOST = something.cloud.company)
(PORT = 12345)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME =
something.company)))"
Puede usarlo en reemplazo del SID.
connection = cx_Oracle.connect("username", "pw", "(DESCRIPTION = (ADDRESS =
(PROTOCOL = TCP)(HOST = something.cloud.company)(PORT = 12345)) (ADDRESS =
(PROTOCOL = TCP)(HOST = something.cloud.company)(PORT = 12345))
(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = something.company)))")
Para aquellos que buscan cómo especificar service_name en lugar de SID.
Del changelog de changelog para SQLAlchemy 1.0.0b1 (lanzado el 13 de marzo de 2015):
[oracle] [feature] Se agregó soporte para conexiones de cx_oracle a un nombre de servicio específico, a diferencia de un nombre de tns, pasando
?service_name=<name>
a la URL. Solicitud de extracción cortesía de Sławomir Ehlert.
El cambio introduce una nueva opción específica de dialecto de Oracle service_name
que se puede usar para construir una cadena de conexión como esta:
from sqlalchemy import create_engine
from sqlalchemy.engine import url
connect_url = url.URL(
''oracle+cx_oracle'',
username=''some_username'',
password=''some_password'',
host=''some_host'',
port=''some_port'',
query=dict(service_name=''some_oracle_service_name''))
engine = create_engine(connect_url)
Si usa sqlalchemy y ORACLE 12, lo siguiente parece funcionar.
from sqlalchemy import create_engine
con=''oracle://user:password@hostname:1521/?service_name=DDDD''
engine = create_engine(con)
Tenga en cuenta que debe usar el nombre del servicio y no el SID. No sé por qué, pero la cadena de conexión simple que usa SID no funciona.
También conocí este problema. La solucion es:
1: get the service name at tnsnames.ora
2: put the service name in
con_str = "myuser/[email protected]:1521/ora1"
Todavía puede no funcionar. Debe tomar el resultado de dsnStr y modificar la cadena reemplazando SID con SERVICE_NAME y usar esa variable en la cadena de conexión. Este procedimiento funcionó para mí.