cx_Oracle не подключается при использовании SID вместо имени службы в строке подключения

У меня есть строка подключения, которая выглядит так:

con_str = "myuser/[email protected]:1521/ora1"

Где ora1 - SID моей базы данных. Использование этой информации в SQL Developer отлично работает, что означает, что я могу подключаться и запрашивать без проблем.

Однако, если я попытаюсь подключиться к Oracle с помощью этой строки, это не сработает.

cx_Oracle.connect(con_str)

DatabaseError:  ORA-12514:  TNS:listener  does  not  currently  know  of  service  requested  in  connect  descriptor

Этот формат строки соединения работает, если ora1 является именем службы.

Я видел другие вопросы, которые, похоже, обращаются к моей проблеме (он работает с SID, но не с именем службы)

Каким образом можно подключиться к Oracle, используя cx_Oracle, используя SID а не имя службы? Как это сделать без необходимости корректировки файла TNSNAMES.ORA? Мое приложение распространено среди многих пользователей внутри страны, и внесение изменений в файл TNSNAMES является менее идеальным при работе с пользователями без прав администратора на их машинах Windows. Кроме того, когда я использую имя службы, мне не нужно вообще прикасаться к этому файлу и хотелось бы, чтобы он поддерживал его таким образом.

Ответы

Ответ 1

Я похож на сценарий, мне удалось подключиться к базе данных с помощью cx_Oracle.makedsn() для создания строки dsn с заданным SID (вместо имени службы):

dsnStr = cx_Oracle.makedsn("oracle.sub.example.com", "1521", "ora1")

Это возвращает что-то вроде

(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle.sub.example.com)(PORT=1521)))(CONNECT_DATA=(SID=ora1)))

который затем можно использовать с cx_Oracle.connect() для подключения к базе данных:

con = cx_Oracle.connect(user="myuser", password="mypass", dsn=dsnStr)
print con.version
con.close()

Ответ 2

Для тех, кто ищет, как указать имя_службы вместо SID.

Из журнала изменений для SQLAlchemy 1.0.0b1 (выпущен 13 марта 2015 г.):

[oracle] [feature] Добавлена поддержка соединений cx_oracle с определенным именем службы, в отличие от имени tns, путем передачи ?service_name=<name> в URL. Вытяните запрос любезно Sławomir Ehlert.

Это изменение вводит новый специфичный для Oracle диалект service_name который может использоваться для построения строки подключения следующим образом:

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)

Ответ 3

Он все еще может не работать. Вам нужно взять вывод dsnStr и изменить строку, заменив SID на SERVICE_NAME и использовать эту переменную в строке con. Эта процедура работала для меня.

Ответ 4

Если вы используете sqlalchemy и ORACLE 12, похоже, что работает.

from sqlalchemy import create_engine
con='oracle://user:[email protected]:1521/?service_name=DDDD'
engine = create_engine(con)

Обратите внимание: вы должны использовать имя службы, а не идентификатор SID. Я не знаю почему, но простая строка соединения, использующая SID, не работает.

Ответ 5

SID может быть недоступен или вы не можете создать его для своей базы данных.

В моем случае я работаю с клиентской стороны, запрашивая доступ к базе данных облака, поэтому создание SID действительно не имеет смысла.

Вместо этого у вас может быть строка, которая выглядит примерно так:

"(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)))"

Вы можете использовать его вместо 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)))")

Ответ 6

Я также встретился с этой проблемой. Решение:

1: get the service name at tnsnames.ora
2: put the service name in
con_str = "myuser/[email protected]:1521/ora1"