将Oracle服务名称与SQLAlchemy结合使用

将Oracle服务名称与SQLAlchemy结合使用,oracle,sqlalchemy,Oracle,Sqlalchemy,我在使用服务名通过SQLAlchemy连接到Oracle模式时遇到了一个棘手的小问题。这是我的脚本代码。(出于安全原因,尖括号之间的项目为实数占位符) 从sqlalchemy导入创建引擎 如果名称=“\uuuuu main\uuuuuuuu”: 引擎=创建引擎(“oracle+cx\U oracle://:@/devdb”) 结果=engine.execute(“创建表测试表(id号(6),名称VARCHAR2(15)非空)”) 结果=引擎。执行(“下拉表测试表”) 其中“devdb”是服务名

我在使用服务名通过SQLAlchemy连接到Oracle模式时遇到了一个棘手的小问题。这是我的脚本代码。(出于安全原因,尖括号之间的项目为实数占位符)

从sqlalchemy导入创建引擎
如果名称=“\uuuuu main\uuuuuuuu”:
引擎=创建引擎(“oracle+cx\U oracle://:@/devdb”)
结果=engine.execute(“创建表测试表(id号(6),名称VARCHAR2(15)非空)”)
结果=引擎。执行(“下拉表测试表”)
其中“devdb”是服务名称,而不是SID。运行此脚本的结果是堆栈跟踪

(oracle-test)[1]jgoodell@jgoodell-MBP:python$ python example.py 
Traceback (most recent call last):
  File "example.py", line 8, in <module>
    result = engine.execute("create table test_table (id NUMBER(6), name VARCHAR2(15) not NULL)")
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 1621, in execute
    connection = self.contextual_connect(close_with_result=True)
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/engine/base.py", line 1669, in contextual_connect
    self.pool.connect(),
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 272, in connect
    return _ConnectionFairy(self).checkout()
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 425, in __init__
    rec = self._connection_record = pool._do_get()
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 777, in _do_get
    con = self._create_connection()
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 225, in _create_connection
    return _ConnectionRecord(self)
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 318, in __init__
    self.connection = self.__connect()
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/pool.py", line 368, in __connect
    connection = self.__pool._creator()
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/engine/strategies.py", line 80, in connect
    return dialect.connect(*cargs, **cparams)
  File "/Users/jgoodell/.virtualenvs/oracle-test/lib/python2.6/site-packages/sqlalchemy/engine/default.py", line 279, in connect
    return self.dbapi.connect(*cargs, **cparams)
sqlalchemy.exc.DatabaseError: (DatabaseError) ORA-12505: TNS:listener does not currently know of SID given in connect descriptor
 None None
(oracle测试)[1]jgoodell@jgoodell-MBP:python$python example.py
回溯(最近一次呼叫最后一次):
文件“example.py”,第8行,在
结果=engine.execute(“创建表测试表(id号(6),名称VARCHAR2(15)非空)”)
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/engine/base.py”,第1621行,在execute中
连接=self.context\u connect(使用结果=True关闭)
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/engine/base.py”,第1669行,在上下文连接中
self.pool.connect(),
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第272行,在connect中
return _ConnectionFairy(self.checkout())
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第425行,在__
rec=self.\u connection\u record=pool.\u do\u get()
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第777行,在
con=self.\u创建\u连接()
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第225行,在创建连接中
返回连接记录(自身)
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第318行,在__
self.connection=self.\u connect()
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/pool.py”,第368行,在uu connect中
连接=self.\u池.\u创建者()
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/engine/strategies.py”,第80行,在connect中
返回方言。连接(*cargs,**cparams)
文件“/Users/jgoodell/.virtualenvs/oracle test/lib/python2.6/site packages/sqlalchemy/engine/default.py”,第279行,在connect中
返回self.dbapi.connect(*cargs,**cparams)
sqlalchemy.exc.DatabaseError:(DatabaseError)ORA-12505:TNS:listener当前不知道连接描述符中给定的SID
没有

如果“devdb”是一个SID而不是一个服务名,那么这个示例就可以正常工作了,我一直在尝试连接字符串的不同排列,但没有找到任何有效的方法。SQLAlchemy文档中似乎也没有任何内容明确解释如何处理Oracle连接的SID和服务名称。

我发现答案是,您必须使用与tnsnames.ora文件中使用的连接字符串相同的连接字符串,例如“@”后面的连接字符串

从sqlalchemy导入创建引擎
如果名称=“\uuuuu main\uuuuuuuu”:
引擎=创建引擎(“oracle+cx\U oracle://:@(描述=(负载平衡=打开)(故障转移=打开)(地址=(协议=TCP)(主机=)(端口=1521))(连接数据=(服务器=专用)(服务名称=devdb)))                                                                                                                                                   
结果=engine.execute(“创建表测试表(id号(6),名称VARCHAR2(15)非空)”)
结果=引擎。执行(“下拉表测试表”)

这个示例运行得很好,您可以注释掉drop语句并检查DB以查看表是否已创建。

cx\u Oracle支持将服务名称传递给makedsn函数

如果create_engine()API将服务_名称传递给它对makedsn所做的底层调用,那就太好了……类似这样:

oracle = create_engine('oracle://user:pw@host:port', service_name='myservice')

TypeError: Invalid argument(s) 'service_name' sent to create_engine(), using configuration OracleDialect_cx_oracle/QueuePool/Engine.
Please check that the keyword arguments are appropriate for this combination of components.
makedns将创建如下所示的TNS:

oracle = create_engine('oracle://user:pw@host:port', service_name='myservice')

TypeError: Invalid argument(s) 'service_name' sent to create_engine(), using configuration OracleDialect_cx_oracle/QueuePool/Engine.
Please check that the keyword arguments are appropriate for this combination of components.
(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=1530))(CONNECT_DATA=(SID=MYSERVICENAME)))

用“服务类型”替换“SID”使它对我起作用


如果您使用的是flask、sqlalchemy和oracle:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import cx_Oracle

app = Flask(__name__)
dnsStr = cx_Oracle.makedsn('my.host.com', '1530', 'my.service.name')
dnsStr = dnsString.replace('SID', 'SERVICE_NAME')
app.config['SQLALCHEMY_DATABASE_URI'] = 'oracle://myschema:mypassword@' + dnsStr
db = SQLAlchemy(app)

sqlalchemy模块现在可以处理oracle服务名称。请看:

from sqlalchemy.engine import create_engine

DIALECT = 'oracle'
SQL_DRIVER = 'cx_oracle'
USERNAME = 'your_username' #enter your username
PASSWORD = 'your_password' #enter your password
HOST = 'subdomain.domain.tld' #enter the oracle db host url
PORT = 1521 # enter the oracle port number
SERVICE = 'your_oracle_service_name' # enter the oracle db service name
ENGINE_PATH_WIN_AUTH = DIALECT + '+' + SQL_DRIVER + '://' + USERNAME + ':' + PASSWORD +'@' + HOST + ':' + str(PORT) + '/?service_name=' + SERVICE

engine = create_engine(ENGINE_PATH_WIN_AUTH)


#test query
import pandas as pd
test_df = pd.read_sql_query('SELECT * FROM global_name', engine)

@//主机名:端口号/服务名使用@//主机名:端口号/服务名抛出一个(数据库错误)ORA-12541:TNS:no Listener您可以直接执行
cx\u Oracle.makedns('myhost','port',service\u name='MYSERVICENAME')
而不是替换
dnsString.replace('SID','service\u name'))
…我询问了在我的工作场所对
create\u engine()
中的
service\u name
的支持。两天的搜索,只有一个解决方案。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import cx_Oracle

app = Flask(__name__)
dnsStr = cx_Oracle.makedsn('my.host.com', '1530', 'my.service.name')
dnsStr = dnsString.replace('SID', 'SERVICE_NAME')
app.config['SQLALCHEMY_DATABASE_URI'] = 'oracle://myschema:mypassword@' + dnsStr
db = SQLAlchemy(app)
from sqlalchemy.engine import create_engine

DIALECT = 'oracle'
SQL_DRIVER = 'cx_oracle'
USERNAME = 'your_username' #enter your username
PASSWORD = 'your_password' #enter your password
HOST = 'subdomain.domain.tld' #enter the oracle db host url
PORT = 1521 # enter the oracle port number
SERVICE = 'your_oracle_service_name' # enter the oracle db service name
ENGINE_PATH_WIN_AUTH = DIALECT + '+' + SQL_DRIVER + '://' + USERNAME + ':' + PASSWORD +'@' + HOST + ':' + str(PORT) + '/?service_name=' + SERVICE

engine = create_engine(ENGINE_PATH_WIN_AUTH)


#test query
import pandas as pd
test_df = pd.read_sql_query('SELECT * FROM global_name', engine)