SqlAlchemy 2.0 中文文档(五十一)(4)https://developer.aliyun.com/article/1563199
Unicode
对于 Python 3 下的所有 DBAPI,所有字符串都是本质上的 Unicode 字符串。然而,在所有情况下,驱动程序都需要明确的编码配置。
确保正确的客户端编码
几乎所有与 Oracle 相关的软件建立客户端编码的长期接受标准是通过NLS_LANG环境变量。cx_Oracle 像大多数其他 Oracle 驱动程序一样将使用此环境变量作为其编码配置的来源。此变量的格式是特殊的;典型值可能是AMERICAN_AMERICA.AL32UTF8
。
cx_Oracle 驱动程序还支持一种编程替代方案,即直接将encoding
和nencoding
参数传递给其.connect()
函数。这些可以在 URL 中如下所示:
engine = create_engine("oracle+cx_oracle://scott:tiger@orclpdb/?encoding=UTF-8&nencoding=UTF-8")
有关encoding
和nencoding
参数的含义,请参阅字符集和国家语言支持(NLS)。
另请参阅
在 cx_Oracle 文档中 字符集和国家语言支持 (NLS)。
Unicode 特定的列数据类型
核心表达语言通过使用 Unicode
和 UnicodeText
数据类型处理 Unicode 数据。这些类型默认对应于 VARCHAR2 和 CLOB Oracle 数据类型。当使用这些数据类型处理 Unicode 数据时,期望 Oracle 数据库配置有 Unicode-aware 字符集,并且 NLS_LANG
环境变量已适当设置,以便 VARCHAR2 和 CLOB 数据类型能够容纳数据。
如果 Oracle 数据库未配置 Unicode 字符集,则有两种选择:显式使用 NCHAR
和 NCLOB
数据类型,或者在调用 create_engine()
时传递标志 use_nchar_for_unicode=True
,这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 替代 VARCHAR/CLOB 用于 Unicode
/ UnicodeText
数据类型。
1.3 版本更改:Unicode
和 UnicodeText
数据类型现在默认对应于 VARCHAR2
和 CLOB
Oracle 数据类型,除非在调用 create_engine()
时传递了 use_nchar_for_unicode=True
。
编码错误
对于 Oracle 数据库中存在损坏编码的情况,方言接受一个参数 encoding_errors
,该参数将传递给 Unicode 解码函数,以影响如何处理解码错误。该值最终由 Python decode 函数消耗,并且通过 cx_Oracle 的 encodingErrors
参数和 SQLAlchemy 自己的解码函数传递,因为在不同情况下 cx_Oracle 方言都会使用它们。
新版本 1.3.11 的新增功能:### 通过 setinputsizes 实现对 cx_Oracle 数据绑定性能的精细控制
cx_Oracle DBAPI 对 DBAPI setinputsizes()
调用具有深刻且基本的依赖关系。此调用的目的是为了为作为参数传递的 Python 值绑定到 SQL 语句的数据类型。虽然几乎没有其他 DBAPI 对setinputsizes()
调用分配任何用途,但 cx_Oracle DBAPI 在与 Oracle 客户端接口的交互中严重依赖它,在某些情况下,SQLAlchemy 不可能知道数据应该如何绑定,因为某些设置可能导致完全不同的性能特征,同时还改变了类型强制转换行为。
使用 cx_Oracle 方言的用户强烈建议阅读 cx_Oracle 内置数据类型符号列表,网址为cx-oracle.readthedocs.io/en/latest/api_manual/module.html#database-types
。请注意,在某些情况下,使用这些类型可能会导致显著的性能下降,尤其是在指定cx_Oracle.CLOB
时。
在 SQLAlchemy 方面,可以使用DialectEvents.do_setinputsizes()
事件来实现运行时可见性(例如日志记录)和完全控制每个语句上如何使用setinputsizes()
。
版本 1.2.9 中新增:添加了DialectEvents.setinputsizes()
示例 1 - 记录所有 setinputsizes 调用
下面的示例说明了如何在将其转换为原始setinputsizes()
参数字典之前,从 SQLAlchemy 视角记录中间值。字典的键是具有.key
和.type
属性的BindParameter
对象:
from sqlalchemy import create_engine, event engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _log_setinputsizes(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in inputsizes.items(): log.info( "Bound parameter name: %s SQLAlchemy type: %r " "DBAPI object: %s", bindparam.key, bindparam.type, dbapitype)
示例 2 - 删除所有与 CLOB 的绑定
在 cx_Oracle 中,CLOB
数据类型会导致显著的性能开销,但在 SQLAlchemy 1.2 系列中默认为Text
类型。可以按以下方式修改此设置:
from sqlalchemy import create_engine, event from cx_Oracle import CLOB engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _remove_clob(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in list(inputsizes.items()): if dbapitype is CLOB: del inputsizes[bindparam] ```### RETURNING 支持 cx_Oracle 方言使用 OUT 参数实现 RETURNING。该方言完全支持 RETURNING。### LOB 数据类型 LOB 数据类型指的是诸如 CLOB、NCLOB 和 BLOB 等“大对象”数据类型。cx_Oracle 和 oracledb 的现代版本经过优化,使得这些数据类型能够作为单个缓冲区传递。因此,默认情况下,SQLAlchemy 使用这些较新的类型处理程序。 要禁用较新的类型处理程序,并将 LOB 对象作为具有`read()`方法的经典缓冲对象传递,请将参数`auto_convert_lobs=False`传递给`create_engine()`,该参数仅对整个引擎生效。 ### 不支持两阶段事务 由于驱动程序支持不佳,cx_Oracle 不支持两阶段事务。 从 cx_Oracle 6.0b1 开始,两阶段事务的接口已更改为更直接地通过底层 OCI 层进行传递,并减少了自动化。 支持此系统的附加逻辑未在 SQLAlchemy 中实现。 ### 精确数字 SQLAlchemy 的数字类型可以将值作为 Python `Decimal` 对象或 float 对象接收和返回。 当使用 `Numeric` 对象或其子类(如 `Float`,`DOUBLE_PRECISION` 等)时, `Numeric.asdecimal` 标志决定是否应在返回时将值强制转换为 `Decimal`,或以 float 对象返回。 在 Oracle 下情况更加复杂,如果“scale”为零,Oracle 的 `NUMBER` 类型还可以表示整数值,因此 Oracle 特定的 `NUMBER` 类型也考虑了这一点。 cx_Oracle 方言广泛使用连接和游标级别的“outputtypehandler”可调用来根据需要强制转换数值。 这些可调用是针对正在使用的具体 `Numeric` 的特定风味的,以及如果不存在 SQLAlchemy 类型化对象。 已观察到的情况包括 Oracle 可能发送有关返回的数字类型的不完整或模糊信息的情况,例如查询,其中数字类型被嵌套在多个子查询的多个级别下。 类型处理程序在所有情况下都尽力做出正确的决定,在所有情况下都将决策委托给底层的 cx_Oracle DBAPI,以便在驱动程序可以做出最佳决策的所有情况下进行。 当不存在类型化对象时,例如在执行纯 SQL 字符串时,存在默认的“outputtypehandler”,该处理程序通常将指定精度和比例的数字值作为 Python `Decimal` 对象返回。 为了性能原因禁用此转换为十进制数的操作,请将标志 `coerce_to_decimal=False` 传递给 `create_engine()`: ```py engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)
coerce_to_decimal
标志仅影响与 Numeric
SQLAlchemy 类型(或其子类)无关联的纯字符串 SQL 语句的结果。
自 1.2 版本起进行了更改:cx_Oracle 的数字处理系统已经重写,以利用较新的 cx_Oracle 特性以及更好地集成输出类型处理程序。
DBAPI
cx-Oracle 的文档和下载信息(如适用)可在此处获取。
连接
连接字符串:
oracle+cx_oracle://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
DSN vs. 主机名连接
cx_Oracle 提供了几种指示目标数据库的方法。方言将一系列不同的 URL 形式进行转换。
使用简易连接语法连接主机名
给定目标 Oracle 数据库的主机名、端口和服务名,例如来自 Oracle 的简易连接语法,然后在 SQLAlchemy 中使用service_name
查询字符串参数进行连接:
engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:port/?service_name=myservice&encoding=UTF-8&nencoding=UTF-8")
不支持完整的简易连接语法。而是使用tnsnames.ora
文件,并使用 DSN 进行连接。
使用 tnsnames.ora 或 Oracle Cloud 进行连接
或者,如果未提供端口、数据库名称或service_name
,则方言将使用 Oracle DSN “连接字符串”。这将 URL 的“主机名”部分作为数据源名称。例如,如果tnsnames.ora
文件包含如下的网络服务名称myalias
:
myalias = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orclpdb1) ) )
当myalias
是 URL 的主机名部分时,cx_Oracle 方言将连接到此数据库服务,而不指定端口、数据库名称或service_name
:
engine = create_engine("oracle+cx_oracle://scott:tiger@myalias/?encoding=UTF-8&nencoding=UTF-8")
Oracle Cloud 的用户应使用此语法,并按照 cx_Oracle 文档连接到 Autonomous 数据库中所示配置云钱包。
SID 连接
要使用 Oracle 的过时 SID 连接语法,可以如下传递 SID 在 URL 的“数据库名称”部分:
engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:1521/dbname?encoding=UTF-8&nencoding=UTF-8")
在上述代码中,传递给 cx_Oracle 的 DSN 由cx_Oracle.makedsn()
创建,如下所示:
>>> import cx_Oracle >>> cx_Oracle.makedsn("hostname", 1521, sid="dbname") '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SID=dbname)))'
使用简易连接语法连接主机名
给定目标 Oracle 数据库的主机名、端口和服务名,例如来自 Oracle 的简易连接语法,然后在 SQLAlchemy 中使用service_name
查询字符串参数进行连接:
engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:port/?service_name=myservice&encoding=UTF-8&nencoding=UTF-8")
不支持完整的简易连接语法。而是使用tnsnames.ora
文件,并使用 DSN 进行连接。
使用 tnsnames.ora 或 Oracle Cloud 进行连接
或者,如果没有提供端口、数据库名称或service_name
,则方言将使用 Oracle DSN “连接字符串”。这将 URL 的“主机名”部分作为数据源名称。例如,如果tnsnames.ora
文件包含如下的网络服务名myalias
:
myalias = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orclpdb1) ) )
当myalias
是 URL 的主机名部分时,cx_Oracle 方言将连接到此数据库服务,而不指定端口、数据库名称或service_name
:
engine = create_engine("oracle+cx_oracle://scott:tiger@myalias/?encoding=UTF-8&nencoding=UTF-8")
Oracle Cloud 的用户应使用此语法,并按照 cx_Oracle 文档中显示的方式配置云钱包连接到自主数据库。
SID 连接
要使用 Oracle 的过时 SID 连接语法,SID 可以在 URL 的“数据库名称”部分中传递,如下所示:
engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:1521/dbname?encoding=UTF-8&nencoding=UTF-8")
上面,传递给 cx_Oracle 的 DSN 是通过cx_Oracle.makedsn()
创建的,如下所示:
>>> import cx_Oracle >>> cx_Oracle.makedsn("hostname", 1521, sid="dbname") '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SID=dbname)))'
传递 cx_Oracle 连接参数
通常可以通过 URL 查询字符串传递其他连接参数;像cx_Oracle.SYSDBA
这样的特殊符号将被拦截并转换为正确的符号:
e = create_engine( "oracle+cx_oracle://user:pass@dsn?encoding=UTF-8&nencoding=UTF-8&mode=SYSDBA&events=true")
从版本 1.3 开始:cx_oracle 方言现在接受 URL 字符串中的所有参数名称,以传递给 cx_Oracle DBAPI。与早期情况相同但没有正确记录的是,create_engine.connect_args
参数也接受所有 cx_Oracle DBAPI 连接参数。
要直接传递参数给.connect()
而不使用查询字符串,请使用create_engine.connect_args
字典。可以传递任何 cx_Oracle 参数值和/或常量,例如:
import cx_Oracle e = create_engine( "oracle+cx_oracle://user:pass@dsn", connect_args={ "encoding": "UTF-8", "nencoding": "UTF-8", "mode": cx_Oracle.SYSDBA, "events": True } )
请注意,在 cx_Oracle 8.0 中,encoding
和nencoding
的默认值已更改为“UTF-8”,因此在使用该版本或更高版本时可以省略这些参数。
SQLAlchemy cx_Oracle 方言在驱动程序之外消耗的选项
还有一些选项是由 SQLAlchemy cx_oracle 方言本身消耗的。这些选项始终直接传递给create_engine()
,例如:
e = create_engine( "oracle+cx_oracle://user:pass@dsn", coerce_to_decimal=False)
cx_oracle 方言接受的参数如下:
arraysize
- 设置光标上的 cx_oracle.arraysize 值;默认为None
,表示应使用驱动程序的默认值(通常值为 100)。此设置控制在提取行时缓冲多少行,并且在修改时可能会对性能产生显着影响。该设置用于cx_Oracle
以及oracledb
。
改变版本 2.0.26:- 将默认值从 50 更改为 None,以使用驱动程序本身的默认值。auto_convert_lobs
- 默认为 True;请参阅 LOB 数据类型。coerce_to_decimal
- 详情请参阅精确数字。encoding_errors
- 详情请参阅编码错误。
使用 cx_Oracle SessionPool
cx_Oracle 库提供了自己的连接池实现,可以代替 SQLAlchemy 的池功能。这可以通过使用 create_engine.creator
参数提供一个返回新连接的函数,以及将 create_engine.pool_class
设置为 NullPool
来实现禁用 SQLAlchemy 的池:
import cx_Oracle from sqlalchemy import create_engine from sqlalchemy.pool import NullPool pool = cx_Oracle.SessionPool( user="scott", password="tiger", dsn="orclpdb", min=2, max=5, increment=1, threaded=True, encoding="UTF-8", nencoding="UTF-8" ) engine = create_engine("oracle+cx_oracle://", creator=pool.acquire, poolclass=NullPool)
然后可以正常使用上述引擎,其中 cx_Oracle 的池处理连接池:
with engine.connect() as conn: print(conn.scalar("select 1 FROM dual"))
除了为多用户应用程序提供可扩展的解决方案外,cx_Oracle 会话池还支持一些 Oracle 功能,例如 DRCP 和应用程序连续性。
使用 Oracle 数据库常驻连接池(DRCP)
当使用 Oracle 的DRCP时,最佳实践是在从 SessionPool 获取连接时传递连接类和“纯度”。参考 cx_Oracle DRCP 文档。
这可以通过包装 pool.acquire()
来实现:
import cx_Oracle from sqlalchemy import create_engine from sqlalchemy.pool import NullPool pool = cx_Oracle.SessionPool( user="scott", password="tiger", dsn="orclpdb", min=2, max=5, increment=1, threaded=True, encoding="UTF-8", nencoding="UTF-8" ) def creator(): return pool.acquire(cclass="MYCLASS", purity=cx_Oracle.ATTR_PURITY_SELF) engine = create_engine("oracle+cx_oracle://", creator=creator, poolclass=NullPool)
然后可以正常使用上述引擎,其中 cx_Oracle 处理会话池,Oracle 数据库另外使用 DRCP:
with engine.connect() as conn: print(conn.scalar("select 1 FROM dual"))
Unicode
对于 Python 3 下的所有 DBAPI,所有字符串本质上都是 Unicode 字符串。然而,在所有情况下,驱动程序都需要明确的编码配置。
确保正确的客户端编码
几乎所有与 Oracle 相关的软件的建立客户端编码的长期接受标准是通过NLS_LANG环境变量。像大多数其他 Oracle 驱动程序一样,cx_Oracle 将使用此环境变量作为其编码配置的源。该变量的格式是特殊的;典型值可能是 AMERICAN_AMERICA.AL32UTF8
。
cx_Oracle 驱动程序还支持一种编程替代方法,即直接将 encoding
和 nencoding
参数传递给其 .connect()
函数。这些可以在 URL 中存在如下:
engine = create_engine("oracle+cx_oracle://scott:tiger@orclpdb/?encoding=UTF-8&nencoding=UTF-8")
关于 encoding
和 nencoding
参数的含义,请参阅字符集和国家语言支持(NLS)。
另请参阅
字符集和国家语言支持 (NLS) - 在 cx_Oracle 文档中。
Unicode 特定的列数据类型
核心表达式语言通过使用 Unicode
和 UnicodeText
数据类型处理 Unicode 数据。这些类型默认对应于 VARCHAR2 和 CLOB Oracle 数据类型。当使用这些数据类型处理 Unicode 数据时,期望 Oracle 数据库配置了 Unicode-aware 字符集,并且 NLS_LANG
环境变量被适当设置,以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。
如果 Oracle 数据库未配置为 Unicode 字符集,则两个选项是显式使用 NCHAR
和 NCLOB
数据类型,或者在调用 create_engine()
时传递 use_nchar_for_unicode=True
标志,这将导致 SQLAlchemy 方言对 Unicode
/ UnicodeText
数据类型使用 NCHAR/NCLOB 而不是 VARCHAR/CLOB。
版本 1.3 中的变更:Unicode
和 UnicodeText
数据类型现在对应于 VARCHAR2
和 CLOB
Oracle 数据类型,除非在调用 create_engine()
时传递了 use_nchar_for_unicode=True
参数给方言。
编码错误
对于 Oracle 数据库中数据存在破损编码的特殊情况,方言接受一个名为 encoding_errors
的参数,该参数将传递给 Unicode 解码函数,以影响如何处理解码错误。该值最终由 Python 的 decode 函数消耗,并且通过 cx_Oracle 的 encodingErrors
参数(由 Cursor.var()
消耗)以及 SQLAlchemy 自己的解码函数传递,因为在不同情况下 cx_Oracle 方言都会使用它们。
新版本 1.3.11 中新增。
确保正确的客户端编码
几乎所有与 Oracle 相关的软件建立客户端编码的长期接受标准是通过 NLS_LANG 环境变量。cx_Oracle 像大多数其他 Oracle 驱动程序一样将使用此环境变量作为其编码配置的来源。该变量的格式是特殊的;典型值可能是 AMERICAN_AMERICA.AL32UTF8
。
cx_Oracle 驱动程序还支持一种编程方式,即直接将 encoding
和 nencoding
参数传递给其 .connect()
函数。可以在 URL 中以以下方式存在:
engine = create_engine("oracle+cx_oracle://scott:tiger@orclpdb/?encoding=UTF-8&nencoding=UTF-8")
关于 encoding
和 nencoding
参数的含义,请参阅字符集和国家语言支持(NLS)。
参见
字符集和国家语言支持(NLS) - 在 cx_Oracle 文档中。
Unicode 特定列数据类型
核心表达式语言通过使用 Unicode
和 UnicodeText
数据类型处理 Unicode 数据。这些类型默认对应于 VARCHAR2 和 CLOB Oracle 数据类型。当使用这些数据类型处理 Unicode 数据时,预期 Oracle 数据库已配置为使用 Unicode 意识字符集,并且 NLS_LANG
环境变量已适当设置,以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。
如果 Oracle 数据库未配置为 Unicode 字符集,则两个选项是显式使用 NCHAR
和 NCLOB
数据类型,或者在调用 create_engine()
时传递标志 use_nchar_for_unicode=True
给 SQLAlchemy 方言,这将导致 SQLAlchemy 方言在 Unicode / UnicodeText 数据类型上使用 NCHAR/NCLOB 而不是 VARCHAR/CLOB。
从版本 1.3 开始更改:Unicode
和 UnicodeText
数据类型现在对应于 VARCHAR2
和 CLOB
Oracle 数据类型,除非在调用 create_engine()
时传递了 use_nchar_for_unicode=True
。
编码错误
对于 Oracle 数据库中存在损坏编码的特殊情况,该方言接受一个名为 encoding_errors
的参数,该参数将传递给 Unicode 解码函数,以影响如何处理解码错误。该值最终由 Python 的 decode 函数消耗,并且通过 cx_Oracle 的 encodingErrors
参数传递给 Cursor.var()
,以及通过 SQLAlchemy 自己的解码函数传递,因为在不同情况下 cx_Oracle 方言都会使用两者。
自版本 1.3.11 起新增。
使用 setinputsizes 对 cx_Oracle 数据绑定性能进行精细控制
cx_Oracle DBAPI 对 DBAPI setinputsizes()
调用具有深层且根本的依赖性。此调用的目的是为通过参数传递的 Python 值绑定到 SQL 语句的数据类型建立起来。虽然几乎没有其他 DBAPI 将任何用途分配给 setinputsizes()
调用,但是 cx_Oracle DBAPI 在与 Oracle 客户端接口的交互中大量依赖它,并且在某些情况下,SQLAlchemy 无法确切地知道数据应该如何绑定,因为某些设置可能会导致性能特性发生深刻不同,同时改变类型强制转换行为。
强烈建议 cx_Oracle 方言的用户阅读 cx_Oracle 内置数据类型符号的列表,网址为 cx-oracle.readthedocs.io/en/latest/api_manual/module.html#database-types
。请注意,在某些情况下,使用这些类型与不使用这些类型相比,性能可能会显著下降,特别是在指定 cx_Oracle.CLOB
时。
在 SQLAlchemy 方面,DialectEvents.do_setinputsizes()
事件可用于在运行时(例如记录)可见 setinputsizes 步骤,以及完全控制每个语句如何使用 setinputsizes()
。
自版本 1.2.9 起新增:增加了 DialectEvents.setinputsizes()
示例 1 - 记录所有 setinputsizes 调用
以下示例说明了如何在转换为原始 setinputsizes()
参数字典之前从 SQLAlchemy 视角记录中间值。字典的键是具有 .key
和 .type
属性的 BindParameter
对象:
from sqlalchemy import create_engine, event engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _log_setinputsizes(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in inputsizes.items(): log.info( "Bound parameter name: %s SQLAlchemy type: %r " "DBAPI object: %s", bindparam.key, bindparam.type, dbapitype)
示例 2 - 移除所有对 CLOB 的绑定
在 cx_Oracle 中,CLOB
数据类型会导致显着的性能开销,但是在 SQLAlchemy 1.2 系列中,默认为 Text
类型设置了该类型。可以按照以下方式修改此设置:
from sqlalchemy import create_engine, event from cx_Oracle import CLOB engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _remove_clob(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in list(inputsizes.items()): if dbapitype is CLOB: del inputsizes[bindparam]
示例 1 - 记录所有 setinputsizes 调用
以下示例说明了如何在 SQLAlchemy 视角下记录中间值,然后再将它们转换为原始setinputsizes()
参数字典。字典的键是具有.key
和.type
属性的BindParameter
对象:
from sqlalchemy import create_engine, event engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _log_setinputsizes(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in inputsizes.items(): log.info( "Bound parameter name: %s SQLAlchemy type: %r " "DBAPI object: %s", bindparam.key, bindparam.type, dbapitype)
示例 2 - 删除所有对 CLOB 的绑定
在 cx_Oracle 中,CLOB
数据类型会产生显着的性能开销,但在 SQLAlchemy 1.2 系列中默认设置为Text
类型。可以按以下方式修改此设置:
from sqlalchemy import create_engine, event from cx_Oracle import CLOB engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe") @event.listens_for(engine, "do_setinputsizes") def _remove_clob(inputsizes, cursor, statement, parameters, context): for bindparam, dbapitype in list(inputsizes.items()): if dbapitype is CLOB: del inputsizes[bindparam]
RETURNING 支持
cx_Oracle 方言使用 OUT 参数实现 RETURNING。该方言完全支持 RETURNING。
LOB 数据类型
LOB 数据类型指的是诸如 CLOB、NCLOB 和 BLOB 等“大对象”数据类型。现代版本的 cx_Oracle 和 oracledb 都经过优化,以便将这些数据类型作为单个缓冲区传递。因此,默认情况下 SQLAlchemy 使用这些较新的类型处理程序。
要禁用较新类型处理程序的使用,并将 LOB 对象作为具有read()
方法的经典缓冲对象传递,可以将参数auto_convert_lobs=False
传递给create_engine()
,这仅在整个引擎范围内生效。
不支持两阶段事务
由于 cx_Oracle 的驱动程序支持不佳,cx_Oracle 不支持两阶段事务。从 cx_Oracle 6.0b1 开始,用于两阶段事务的接口已更改为更直接地通过到底层 OCI 层的传递,自动化程度较低。支持此系统的附加逻辑未在 SQLAlchemy 中实现。
精确数值
SQLAlchemy 的数值类型可以处理接收和返回 Python Decimal
对象或浮点对象的值。当使用 Numeric
对象或其子类如 Float
、DOUBLE_PRECISION
等时,Numeric.asdecimal
标志确定返回时值是否应强制转换为 Decimal
,或作为浮点对象返回。在 Oracle 下更加复杂的是,如果“scale”为零,Oracle 的 NUMBER
类型也可以表示整数值,因此 Oracle 特定的 NUMBER
类型也考虑到了这一点。
cx_Oracle 方言广泛使用连接和游标级别的“outputtypehandler”可调用对象,以按请求强制转换数值。这些可调用对象特定于正在使用的特定Numeric
的类型,以及如果没有 SQLAlchemy 类型化对象存在。已经观察到 Oracle 可能会发送关于返回的数值类型不完整或模糊的信息的情况,例如查询,其中数值类型被埋在多级子查询下。类型处理程序尽最大努力在所有情况下做出正确的决定,在所有情况下都推迟到底层 cx_Oracle DBAPI,以便在驱动程序可以做出最佳决定的所有这些情况下。
当没有类型化对象时,例如执行纯 SQL 字符串时,存在一个默认的“outputtypehandler”,通常返回指定精度和比例的数值,其类型为 Python 的Decimal
对象。为了出于性能考虑禁用对十进制数的强制转换,请在create_engine()
中传递标志coerce_to_decimal=False
:
engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)
coerce_to_decimal
标志仅影响不与Numeric
SQLAlchemy 类型(或其子类)相关联的纯字符串 SQL 语句的结果。
从 1.2 版本开始更改:cx_Oracle 的数值处理系统已经重新设计,以利用较新的 cx_Oracle 功能以及更好地集成 outputtypehandlers。
python-oracledb
通过 python-oracledb 驱动程序支持 Oracle 数据库。
DBAPI
有关 python-oracledb 的文档和下载信息(如果适用),请访问:oracle.github.io/python-oracledb/
连接
连接字符串:
oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
python-oracledb 是由 Oracle 发布的,旨在取代 cx_Oracle 驱动程序。它与 cx_Oracle 完全兼容,具有不需要任何依赖项的“轻客户端”模式,以及使用与 cx_Oracle 相同的方式使用 Oracle Client Interface 的“厚客户端”模式。
另请参阅
cx_Oracle - cx_Oracle 的所有注意事项也适用于 oracledb 驱动程序。
SQLAlchemy 的oracledb
方言提供了同名的同步和异步实现。根据引擎的创建方式选择合适的版本:
- 使用
oracle+oracledb://...
调用create_engine()
将自动选择同步版本,例如:
from sqlalchemy import create_engine sync_engine = create_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
- 使用
oracle+oracledb://...
调用create_async_engine()
将自动选择异步版本,例如:
from sqlalchemy.ext.asyncio import create_async_engine asyncio_engine = create_async_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
可以明确指定方言的异步版本,例如使用oracledb_async
后缀:
from sqlalchemy.ext.asyncio import create_async_engine asyncio_engine = create_async_engine("oracle+oracledb_async://scott:tiger@localhost/?service_name=XEPDB1")
新版本 2.0.25 中新增对 oracledb 的异步版本的支持。
Thick mode 支持
默认情况下,python-oracledb
以 thin 模式启动,不需要在系统中安装 Oracle 客户端库。python-oracledb
驱动程序还支持一种“thick”模式,其行为类似于cx_oracle
,并且要求安装 Oracle 客户端接口(OCI)。
要启用此模式,用户可以手动调用oracledb.init_oracle_client
,也可以通过将参数thick_mode=True
传递给create_engine()
来实现。要将自定义参数传递给init_oracle_client
,如lib_dir
路径,则可以将字典传递给此参数,如下所示:
engine = sa.create_engine("oracle+oracledb://...", thick_mode={ "lib_dir": "/path/to/oracle/client/lib", "driver_name": "my-app" })
另请参见
python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client
新版本 2.0.0 中新增对 oracledb 驱动程序的支持。
DBAPI
python-oracledb 的文档和下载信息(如适用)可在此处找到:oracle.github.io/python-oracledb/
连接
连接字符串:
oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
Thick mode 支持
默认情况下,python-oracledb
以 thin 模式启动,不需要在系统中安装 Oracle 客户端库。python-oracledb
驱动程序还支持一种“thick”模式,其行为类似于cx_oracle
,并且要求安装 Oracle 客户端接口(OCI)。
要启用此模式,用户可以手动调用oracledb.init_oracle_client
,也可以通过将参数thick_mode=True
传递给create_engine()
来实现。要将自定义参数传递给init_oracle_client
,如lib_dir
路径,则可以将字典传递给此参数,如下所示:
engine = sa.create_engine("oracle+oracledb://...", thick_mode={ "lib_dir": "/path/to/oracle/client/lib", "driver_name": "my-app" })
另请参见
python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client
新版本 2.0.0 中新增对 oracledb 驱动程序的支持。
不需要任何依赖项的“轻客户端”模式,以及使用与 cx_Oracle 相同的方式使用 Oracle Client Interface 的“厚客户端”模式。
另请参阅
cx_Oracle - cx_Oracle 的所有注意事项也适用于 oracledb 驱动程序。
SQLAlchemy 的oracledb
方言提供了同名的同步和异步实现。根据引擎的创建方式选择合适的版本:
- 使用
oracle+oracledb://...
调用create_engine()
将自动选择同步版本,例如:
from sqlalchemy import create_engine sync_engine = create_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
- 使用
oracle+oracledb://...
调用create_async_engine()
将自动选择异步版本,例如:
from sqlalchemy.ext.asyncio import create_async_engine asyncio_engine = create_async_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
可以明确指定方言的异步版本,例如使用oracledb_async
后缀:
from sqlalchemy.ext.asyncio import create_async_engine asyncio_engine = create_async_engine("oracle+oracledb_async://scott:tiger@localhost/?service_name=XEPDB1")
新版本 2.0.25 中新增对 oracledb 的异步版本的支持。
Thick mode 支持
默认情况下,python-oracledb
以 thin 模式启动,不需要在系统中安装 Oracle 客户端库。python-oracledb
驱动程序还支持一种“thick”模式,其行为类似于cx_oracle
,并且要求安装 Oracle 客户端接口(OCI)。
要启用此模式,用户可以手动调用oracledb.init_oracle_client
,也可以通过将参数thick_mode=True
传递给create_engine()
来实现。要将自定义参数传递给init_oracle_client
,如lib_dir
路径,则可以将字典传递给此参数,如下所示:
engine = sa.create_engine("oracle+oracledb://...", thick_mode={ "lib_dir": "/path/to/oracle/client/lib", "driver_name": "my-app" })
另请参见
python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client
新版本 2.0.0 中新增对 oracledb 驱动程序的支持。
DBAPI
python-oracledb 的文档和下载信息(如适用)可在此处找到:oracle.github.io/python-oracledb/
连接
连接字符串:
oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
Thick mode 支持
默认情况下,python-oracledb
以 thin 模式启动,不需要在系统中安装 Oracle 客户端库。python-oracledb
驱动程序还支持一种“thick”模式,其行为类似于cx_oracle
,并且要求安装 Oracle 客户端接口(OCI)。
要启用此模式,用户可以手动调用oracledb.init_oracle_client
,也可以通过将参数thick_mode=True
传递给create_engine()
来实现。要将自定义参数传递给init_oracle_client
,如lib_dir
路径,则可以将字典传递给此参数,如下所示:
engine = sa.create_engine("oracle+oracledb://...", thick_mode={ "lib_dir": "/path/to/oracle/client/lib", "driver_name": "my-app" })
另请参见
python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client
新版本 2.0.0 中新增对 oracledb 驱动程序的支持。