预言机¶
支持 Oracle Database 数据库。
下表总结了数据库发行版的当前支持级别。
|
|
---|---|
11+ |
|
9+ |
DBAPI 支持¶
以下 dialect/DBAPI 选项可用。有关连接信息,请参阅各个 DBAPI 部分。
自动递增行为¶
包含整数主键的 SQLAlchemy Table 对象通常被假定为具有“自动递增”行为,这意味着它们可以在 INSERT 时生成自己的主键值。要在 Oracle Database 中使用,有两个选项可用,即使用 IDENTITY 列(仅限 Oracle Database 12 及更高版本)或 SEQUENCE 与列的关联。
指定 GENERATED AS IDENTITY (Oracle Database 12 及更高版本)¶
从版本 12 开始,Oracle Database 可以通过 Identity 来指定自动递增行为,从而使用标识
列:
t = Table(
"mytable",
metadata,
Column("id", Integer, Identity(start=3), primary_key=True),
Column(...),
...,
)
上述 Table
对象的 CREATE TABLE 将为:
CREATE TABLE mytable (
id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3),
...,
PRIMARY KEY (id)
)
Identity
对象支持许多选项来控制列的 “自动递增” 行为,例如起始值、递增值等。除了标准选项之外,Oracle Database 还支持将 Identity.always
设置为 None
以使用默认生成模式,在 DDL 中呈现 GENERATED AS IDENTITY。它还支持将 Identity.on_null
设置为 True
,以将 ON NULL 与 'BY DEFAULT' 标识列一起指定。
使用 SEQUENCE (所有 Oracle Database 版本)¶
旧版本的 Oracle Database 没有“自动递增”功能:SQLAlchemy 依赖序列来生成这些值。对于较旧的 Oracle Database 版本,必须始终显式指定序列以启用
autoincrement 的这与大多数文档示例不同,这些示例假定使用支持自动增量的数据库。要指定序列,请使用传递给 Column 构造的 sqlalchemy.schema.Sequence 对象:
t = Table(
"mytable",
metadata,
Column("id", Integer, Sequence("id_seq", start=1), primary_key=True),
Column(...),
...,
)
使用表反射时也需要此步骤,即 autoload_with=engine:
t = Table(
"mytable",
metadata,
Column("id", Integer, Sequence("id_seq", start=1), primary_key=True),
autoload_with=engine,
)
事务隔离级别 / 自动提交¶
Oracle Database 支持“READ COMMITTED”和“SERIALIZABLE”隔离模式。python-oracledb 和 cx_Oracle 方言也支持 AUTOCOMMIT 隔离级别。
要使用每个连接的执行选项进行设置,请执行以下作:
connection = engine.connect()
connection = connection.execution_options(isolation_level="AUTOCOMMIT")
对于 READ COMMITTED
和 SERIALIZABLE,Oracle
Database dialects 使用 ALTER SESSION
在会话级别设置级别,当连接返回到连接池时,该级别将恢复为默认设置。
isolation_level
的有效值包括:
读取已提交
自动提交
序列 化
注意
的
Connection.get_isolation_level()
方法必然会强制使用 Oracle Database DBMS_TRANSACTION启动事务。LOCAL_TRANSACTION_ID功能;否则,通常不可读任何级别。
此外, Connection.get_isolation_level()
如果 v$transaction
视图由于权限或其他原因而不可用,该方法将引发异常,这在 Oracle Database 安装中很常见。
python-oracledb 和 cx_Oracle 方言尝试调用
Connection.get_isolation_level()
方法,当 dialect 使
它与数据库的第一次连接,以便获取
“default” 隔离级别。 此默认级别是必需的,因此级别
可以在使用临时修改连接后在连接上重置
Connection.execution_options()
方法。在 Connection.get_isolation_level()
该方法由于 v$transaction
不可读以及任何其他与数据库相关的故障而引发异常的常见事件中,假定级别为“READ COMMITTED”。对于此初始首次连接条件,不会发出警告,因为它预计是 Oracle 数据库的常见限制。
在 1.3.16 版本加入: 添加了对 cx_Oracle 方言的 AUTOCOMMIT 的支持以及默认隔离级别的概念
1.3.21 版本中的新功能: 添加了对 SERIALIZABLE 以及隔离级别的实时读取的支持。
在 1.3.22 版本发生变更: 如果由于 v$transaction 视图的权限而无法读取默认隔离级别(这在 Oracle 安装中很常见),则默认隔离级别将硬编码为“READ COMMITTED”,这是 1.3.21 之前的行为。
标识符大小写¶
在 Oracle Database 中,数据字典使用 UPPERCASE 文本表示所有不区分大小写的标识符名称。另一方面,SQLAlchemy 将全小写标识符名称视为不区分大小写。Oracle Database dialect 在架构级别通信(例如表和索引的反射)期间将所有不区分大小写的标识符与这两种格式相互转换。在 SQLAlchemy 端使用大写名称表示区分大小写的标识符,SQLAlchemy 将引用该名称 - 这将导致与从 Oracle 数据库接收的数据字典数据不匹配,因此,除非标识符名称确实创建为区分大小写(即使用带引号的名称),否则应在 SQLAlchemy 端使用所有小写名称。
最大标识符长度¶
SQLAlchemy 对 Oracle Database 支持的最大标识符长度敏感。这会影响生成的 SQL 标签名称以及约束名称的生成,尤其是在使用配置约束命名约定中描述的约束命名约定功能的情况下。
Oracle Database 12.2 将默认最大标识符长度从 30 增加到
128. 从 SQLAlchemy 1.4 开始,Oracle 的默认最大标识符长度
dialects 为 128 个字符。 首次连接时,最大长度实际上
得到数据库的支持。在所有情况下,将
create_engine.max_identifier_length
parameter 将绕过此更改,并且给定的值将按原样使用:
engine = create_engine(
"oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1",
max_identifier_length=30,
)
如果未 create_engine.max_identifier_length
设置,则 oracledb 方言在内部使用自 python-oracledb 版本 2.5 以来驱动程序连接上可用的 max_identifier_length
属性。当使用较旧的驱动程序版本或使用 cx_Oracle 方言时,SQLAlchemy 将尝试使用查询 SELECT value FROM v$parameter WHERE name = 'compatible'
首次连接时,为了确定 的有效兼容性版本
数据库。“兼容性”版本是一个版本号,即
独立于实际数据库版本。它用于辅助数据库
迁移。它由 Oracle Database 初始化参数配置。这
然后,兼容版本将确定
数据库。如果 V$ 视图不可用,则数据库版本信息
。
最大标识符长度在 SELECT 语句中生成匿名 SQL 标签时起作用,但在从命名约定生成约束名称时更为关键。正是这个领域产生了 SQLAlchemy 保守地更改此默认值的需求。例如,以下命名约定根据标识符长度生成两个截然不同的约束名称:
from sqlalchemy import Column
from sqlalchemy import Index
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy.dialects import oracle
from sqlalchemy.schema import CreateIndex
m = MetaData(naming_convention={"ix": "ix_%(column_0N_name)s"})
t = Table(
"t",
m,
Column("some_column_name_1", Integer),
Column("some_column_name_2", Integer),
Column("some_column_name_3", Integer),
)
ix = Index(
None,
t.c.some_column_name_1,
t.c.some_column_name_2,
t.c.some_column_name_3,
)
oracle_dialect = oracle.dialect(max_identifier_length=30)
print(CreateIndex(ix).compile(dialect=oracle_dialect))
如果标识符长度为 30,则上面的 CREATE INDEX 如下所示:
CREATE INDEX ix_some_column_name_1s_70cd ON t
(some_column_name_1, some_column_name_2, some_column_name_3)
但是,如果长度为 128,则变为:
.. sourcecode:: sql
CREATE INDEX ix_some_column_name_1some_column_name_2some_column_name_3 ON t (some_column_name_1、 some_column_name_2、 some_column_name_3)
在 Oracle 上运行 SQLAlchemy 1.4 之前的版本的应用程序
因此,数据库版本 12.2 或更高版本受
希望对
以前以较短的长度生成。 在以下情况下,此迁移将失败
标识符长度更改,但不包含索引或约束的名称
首先是 Adjusted。 强烈建议此类应用程序使用
create_engine.max_identifier_length
为了保持对截断名称生成的控制,并在更改此值时在暂存环境中全面审查和测试所有数据库迁移,以确保减轻此更改的影响。
在 1.4 版更改: Oracle Database 的默认max_identifier_length为 128 个字符,如果 Oracle Database 或其兼容性设置低于版本 12.2,则在首次连接时将其调整为 30 个字符。
LIMIT/OFFSET/FETCH 支持¶
Select.limit()
和 Select.offset()
等方法使用 FETCH FIRST N ROW / OFFSET N ROWS
假定 Oracle Database 12c 或
上文,并假设 SELECT 语句未嵌入到复合中
语句(如 UNION)。 此语法也可通过使用
Select.fetch()
方法。
在 2.0 版本发生变更: Oracle Database dialect 现在对所有 FETCH FIRST N
ROW / OFFSET N ROWS
Select.limit()
和
Select.offset()
用法,包括在 ORM 和旧版
Query
查询。要使用窗口函数强制使用旧行为,请将 enable_offset_fetch=False
dialect 参数指定为
create_engine()
中。
通过将 enable_offset_fetch=False
传递给 create_engine()
,可以在任何 Oracle Database 版本上禁用 FETCH FIRST / OFFSET
的使用,这将强制使用使用窗口函数的“传统”模式。使用 12c 之前的 Oracle Database 版本时,也会自动选择此模式。
当使用传统模式时,或者当 Select
语句具有 limit/offset 时
嵌入在复合语句中,这是 LIMIT / OFFSET 的模拟方法
based on window 函数,这涉及使用
ROW_NUMBER
,这容易出现性能问题以及复杂语句的 SQL 构造问题。但是,所有 Oracle Database 版本都支持此方法。请参阅下面的注释。
关于 LIMIT / OFFSET 模拟的注意事项 (当 fetch() 方法不能使用时)¶
如果在 12c 之前的 Oracle 数据库版本上使用 Select.limit()
和 Select.offset(),
或者使用 ORM 使用 Query.limit()
和 Query.offset()
方法,则以下说明适用:
SQLAlchemy 目前使用 ROWNUM 来实现 限制/偏移;确切的方法取自 https://blogs.oracle.com/oraclemagazine/on-rownum-and-limiting-results .
默认情况下不使用 “FIRST_ROWS()” 优化关键字。要启用此优化指令的使用,请指定optimize_limits=True
设置为create_engine()。
在 1.4 版本发生变更: Oracle Database dialect 使用“编译后”方案呈现 limit/offset 整数值,该方案在将语句传递给游标执行之前直接呈现整数。use_binds_for_limits
标志不再有效。
RETURNING 支持¶
Oracle Database 完全支持对使用单个绑定参数集合(即 cursor.execute()
样式语句;SQLAlchemy 通常不支持 RETURNING 和 executemany statements)。也可能返回多行。
在 2.0 版更改: Oracle Database 后端完全支持 RETURNING,与其他后端相同。
更新级联时¶
Oracle Database 没有本机 ON UPDATE CASCADE 功能。 触发器
基于的解决方案可在
https://web.archive.org/web/20090317041251/https://asktom.oracle.com/tkyte/update_cascade/index.html
当使用 SQLAlchemy ORM 时,ORM 手动发出级联更新的能力有限 - 使用 “deferrable=True, initially='deferred'” 关键字参数指定 ForeignKey 对象,并在每个 relationship() 上指定 “passive_updates=False”。
Oracle Database 8 兼容性¶
警告
SQLAlchemy 2.0 的 Oracle Database 8 兼容性状态尚不清楚。
检测到 Oracle Database 8 时,方言会在内部将自身配置为以下行为:
同义词/DBLINK 反射¶
当对 Table 对象使用反射时,方言可以选择在本地或远程架构中或通过 DBLINK 访问由同义词指示的表,方法是将标志 oracle_resolve_synonyms=True
作为关键字参数传递给 Table
构造:
some_table = Table(
"some_table", autoload_with=some_engine, oracle_resolve_synonyms=True
)
设置此标志后,不仅会在 ALL_TABLES
视图中搜索给定名称(如上面的 some_table
),还会在
ALL_SYNONYMS
视图以查看此名称是否实际上是另一个名称的同义词
名字。 如果同义词位于并引用 DBLINK,则 Oracle Database
dialects 知道如何使用 DBLINK 语法(例如
@dblink
)。
只要接受反射参数,就会接受 oracle_resolve_synonyms
,包括 MetaData.reflect()
和
Inspector.get_columns()
中。
如果未使用同义词,则应禁用此标志。
约束反射¶
Oracle Database dialects 可以返回有关外键、唯一和 CHECK 约束以及表索引的信息。
有关这些约束的原始信息可以使用
Inspector.get_foreign_keys()
、
Inspector.get_unique_constraints()
、
Inspector.get_check_constraints()
和
Inspector.get_indexes()
的
在 1.2 版本发生变更: Oracle Database 方言现在可以反映 UNIQUE 和 CHECK 约束。
请注意以下注意事项:
使用Inspector.get_check_constraints()
该方法时,Oracle Database 会为指定 “NOT NULL” 的列构建特殊的 “IS NOT NULL” 约束。默认情况下,不返回此约束;要包含 “IS NOT NULL” 约束,请传递标志include_all=True
:from sqlalchemy import create_engine, inspect engine = create_engine( "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1" ) inspector = inspect(engine) all_check_constraints = inspector.get_check_constraints( "some_table", include_all=True )
在大多数情况下,在反映Table
时,UNIQUE 约束将不可用作UniqueConstraint
对象,因为在大多数情况下,Oracle Database 使用 UNIQUE 索引镜像唯一约束(当两个或多个唯一约束表示相同的列时,似乎例外);Table
将使用 设置了unique=True
标志的索引
。
Oracle Database 为表的主键创建隐式索引;此索引将从所有索引结果中排除。
索引反映的列列表将不包含以 SYS_NC 开头的列名。
带有 SYSTEM/SYSAUX 表空间的表名¶
Inspector.get_table_names()
和
Inspector.get_temp_table_names()
方法每个方法都返回当前引擎的表名列表。这些方法
也是在作中发生的反射的一部分,例如
MetaData.reflect()
中。默认情况下,这些作不包括 SYSTEM
和 SYSAUX
表空间。为了改变这一点,可以使用 exclude_tablespaces
参数在引擎级别更改排除的表空间的默认列表:
# exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
e = create_engine(
"oracle+oracledb://scott:tiger@localhost:1521/?service_name=freepdb1",
exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"],
)
FLOAT / DOUBLE 支持和行为¶
SQLAlchemy Float
和 Double
数据类型是通用数据类型,可解析为给定后端的“最不令人惊讶”的数据类型。对于 Oracle Database,这意味着它们解析为 FLOAT
和 DOUBLE
类型:
>>> from sqlalchemy import cast, literal, Float
>>> from sqlalchemy.dialects import oracle
>>> float_datatype = Float()
>>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
CAST(:param_1 AS FLOAT)
Oracle 的 FLOAT
/ DOUBLE
数据类型是 NUMBER
的别名。Oracle Database 以全精度而不是浮点精度存储 NUMBER
值,这意味着 FLOAT
/DOUBLE
实际上的行为与
原生 FP 值。相反,Oracle 数据库提供特殊数据类型
BINARY_FLOAT
和 BINARY_DOUBLE
来提供实际的 4 字节和 8 字节 FP 值。
SQLAlchemy 使用 BINARY_FLOAT
和
BINARY_DOUBLE
。使用 Float
或 Double
数据类型,同时允许 Oracle 后端使用
以下类型之一,请使用 TypeEngine.with_variant()
方法设置变体:
>>> from sqlalchemy import cast, literal, Float
>>> from sqlalchemy.dialects import oracle
>>> float_datatype = Float().with_variant(oracle.BINARY_FLOAT(), "oracle")
>>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
CAST(:param_1 AS BINARY_FLOAT)
例如,要在 Table
定义中使用此数据类型:
my_table = Table(
"my_table",
metadata,
Column(
"fp_data", Float().with_variant(oracle.BINARY_FLOAT(), "oracle")
),
)
DateTime 兼容性¶
Oracle Database 没有称为 DATETIME
的数据类型,而是只有
DATE,
它实际上可以存储日期和时间值。因此,Oracle Database 方言提供了一个类型 DATE
,它是 DateTime
的子类。此类型没有特殊行为,仅作为此类型的 “标记” 存在;此外,当反映数据库列并且类型报告为 DATE
时,支持时间的
DATE
类型。
Oracle 数据库表选项¶
CREATE TABLE 短语支持 Oracle Database 方言和 Table
构造的以下选项:
提交时
:Table( "some_table", metadata, ..., prefixes=["GLOBAL TEMPORARY"], oracle_on_commit="PRESERVE ROWS", )
压缩
:Table( "mytable", metadata, Column("data", String(32)), oracle_compress=True ) Table("mytable", metadata, Column("data", String(32)), oracle_compress=6)
oracle_compress
参数接受整数压缩级别,或接受True
以使用默认压缩级别。TABLESPACE
中:Table("mytable", metadata, ..., oracle_tablespace="EXAMPLE_TABLESPACE")
oracle_tablespace
参数指定要在其中创建表的表空间。当您想在用户的默认表空间以外的表空间中创建表时,这非常有用。
2.0.37 新版功能.
Oracle 数据库特定索引选项¶
位图索引¶
您可以指定 oracle_bitmap
参数来创建位图索引,而不是 B 树索引:
Index("my_index", my_table.c.data, oracle_bitmap=True)
位图索引不能唯一且不能压缩。SQLAlchemy 不会检查此类限制,只有数据库会检查。
索引压缩¶
Oracle Database 对包含大量重复值的索引具有更高效的存储模式。使用 oracle_compress
参数打开按键压缩:
Index("my_index", my_table.c.data, oracle_compress=True)
Index(
"my_index",
my_table.c.data1,
my_table.c.data2,
unique=True,
oracle_compress=1,
)
oracle_compress
参数接受一个整数(指定要压缩的前缀列数),或接受 True
以使用默认值(非唯一索引的所有列,唯一索引除最后一列之外的所有列)。
Oracle 数据库数据类型¶
与所有 SQLAlchemy 方言一样,所有已知对 Oracle Database 有效的 UPPERCASE 类型都可以从顶级方言导入,无论它们源自 sqlalchemy.types
还是本地方言:
from sqlalchemy.dialects.oracle import (
BFILE,
BLOB,
CHAR,
CLOB,
DATE,
DOUBLE_PRECISION,
FLOAT,
INTERVAL,
LONG,
NCLOB,
NCHAR,
NUMBER,
NVARCHAR,
NVARCHAR2,
RAW,
TIMESTAMP,
VARCHAR,
VARCHAR2,
)
1.2.19 版本中的新功能: 将 NCHAR
添加到 Oracle 方言导出的数据类型列表中。
特定于 Oracle Database 或具有特定于 Oracle 的构造参数的类型如下:
对象名称 |
描述 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
类 sqlalchemy.dialects.oracle。BFILE(文件)¶
成员-
方法sqlalchemy.dialects.oracle.BFILE.
__init__(length:intNone=None)¶
继承自sqlalchemy.types.LargeBinary.__init__
LargeBinary
的方法
构造 LargeBinary 类型。
参数
length¶ – 可选,用于 DDL 语句的列的长度,适用于接受长度的二进制类型,例如 MySQL BLOB 类型。
-
-
类 sqlalchemy.dialects.oracle。BINARY_DOUBLE¶
实施 OracleBINARY_DOUBLE
数据类型。
此数据类型与 OracleDOUBLE
数据类型的不同之处在于,它提供真正的 8 字节 FP 值。可以使用TypeEngine.with_variant()
将数据类型与通用Double
数据类型组合在一起。
另请参阅
成员-
方法sqlalchemy.dialects.oracle.BINARY_DOUBLE.
__init__(precision:intNone=None, asdecimal: bool = False, decimal_return_scale:intNone=None)¶
继承自sqlalchemy.types.Float.__init__
Float
的方法
构造一个浮点数。
参数
精度¶ –
在 DDL CREATE 中使用的数值精度TABLE
的后端应尝试确保此精度 表示泛型Float
数据类型。
注意
对于 Oracle Database 后端, 渲染 DDL 时不接受Float.precision
参数,因为 Oracle Database 不支持指定为小数位数的浮点精度。相反,请使用特定于 Oracle Database 的FLOAT
数据类型并指定FLOAT.binary_precision
参数。这是 SQLAlchemy 版本 2.0 中的新增功能。
要创建与数据库无关的Float
,请执行 单独指定 Oracle Database 的二进制精度,请使用TypeEngine.with_variant()
如下所示:from sqlalchemy import Column from sqlalchemy import Float from sqlalchemy.dialects import oracle Column( "float_data", Float(5).with_variant(oracle.FLOAT(binary_precision=16), "oracle"), )
asdecimal¶ —— 与Numeric
的标志相同,但默认为False
。请注意,将此标志设置为True
导致浮点转换。
decimal_return_scale¶– 从浮点数转换为 Python 小数时使用的默认比例。由于十进制的不准确,浮点值通常会长得多,并且大多数浮点数据库类型没有“小数位数”的概念,因此默认情况下,浮点类型在转换时查找前十位小数。指定此值将覆盖该长度。请注意,如果未另行指定,则包含 “scale” 的 MySQL 浮点类型将使用 “scale” 作为 decimal_return_scale 的默认值。
-
-
类 sqlalchemy.dialects.oracle。BINARY_FLOAT¶
实现 OracleBINARY_FLOAT
数据类型。
此数据类型与 OracleFLOAT
数据类型的不同之处在于,它提供真正的 4 字节 FP 值。该数据类型可以使用TypeEngine.with_variant()
与通用Float
数据类型组合。
另请参阅
成员-
方法sqlalchemy.dialects.oracle.BINARY_FLOAT.
__init__(precision:intNone=None, asdecimal: bool = False, decimal_return_scale:intNone=None)¶
继承自sqlalchemy.types.Float.__init__
Float
的方法
构造一个浮点数。
参数
精度¶ –
在 DDL CREATE 中使用的数值精度TABLE
的后端应尝试确保此精度 表示泛型Float
数据类型。
注意
对于 Oracle Database 后端, 渲染 DDL 时不接受Float.precision
参数,因为 Oracle Database 不支持指定为小数位数的浮点精度。相反,请使用特定于 Oracle Database 的FLOAT
数据类型并指定FLOAT.binary_precision
参数。这是 SQLAlchemy 版本 2.0 中的新增功能。
要创建与数据库无关的Float
,请执行 单独指定 Oracle Database 的二进制精度,请使用TypeEngine.with_variant()
如下所示:from sqlalchemy import Column from sqlalchemy import Float from sqlalchemy.dialects import oracle Column( "float_data", Float(5).with_variant(oracle.FLOAT(binary_precision=16), "oracle"), )
asdecimal¶ —— 与Numeric
的标志相同,但默认为False
。请注意,将此标志设置为True
导致浮点转换。
decimal_return_scale¶– 从浮点数转换为 Python 小数时使用的默认比例。由于十进制的不准确,浮点值通常会长得多,并且大多数浮点数据库类型没有“小数位数”的概念,因此默认情况下,浮点类型在转换时查找前十位小数。指定此值将覆盖该长度。请注意,如果未另行指定,则包含 “scale” 的 MySQL 浮点类型将使用 “scale” 作为 decimal_return_scale 的默认值。
-
-
类 sqlalchemy.dialects.oracle。日期¶
提供 Oracle Database DATE 类型。
此类型没有特殊的 Python 行为,只是它是子类日期时间
;这是为了适应 Oracle 数据库DATE
类型支持时间值。
成员
类签名
类sqlalchemy.dialects.oracle.DATE
(sqlalchemy.dialects.oracle.types._OracleDateLiteralRender
,sqlalchemy.types.DateTime
)-
方法sqlalchemy.dialects.oracle.DATE.
__init__(timezone: bool = False)¶
继承自sqlalchemy.types.DateTime.__init__
DateTime
的方法
构造新的DateTime
。
-
-
类 sqlalchemy.dialects.oracle。浮点数(FLOAT)¶
Oracle 数据库 FLOAT。
这与FLOAT
相同,不同之处在于特定于 Oracle Database 的FLOAT.binary_precision
parameter 被接受,并且 不接受Float.precision
参数。
Oracle Database FLOAT 类型以“二进制精度”表示精度,默认为 126。对于 REAL 类型,该值为 63。此参数不会完全映射到特定的小数位数,但大致相当于所需的小数位数除以 0.3103。
2.0 版的新Function。
成员-
方法sqlalchemy.dialects.oracle.FLOAT.
__init__(binary_precision=None, asdecimal=False, decimal_return_scale=None)¶
构造一个 FLOAT
参数
binary_precision¶– 要在 DDL 中呈现的 Oracle 数据库二进制精度值。这可以近似于使用公式“decimal precision = 0.30103 * binary precision”的十进制字符数。Oracle Database 用于 FLOAT / DOUBLE PRECISION 的默认值为 126。
asdecimal¶ – 参见Float.asdecimal
decimal_return_scale¶ – 参见Float.decimal_return_scale
-
-
类 sqlalchemy.dialects.oracle。间隔¶
成员
类签名
类sqlalchemy.dialects.oracle.INTERVAL
(sqlalchemy.types.NativeForEmulated
,sqlalchemy.types._AbstractInterval
)-
方法sqlalchemy.dialects.oracle.INTERVAL.
__init__(day_precision=无, second_precision=无)¶
构造一个 INTERVAL.
请注意,目前仅支持 DAY TO SECOND 间隔。这是因为在可用的 DBAPI 中缺乏对 YEAR TO MONTH 间隔的支持。
-
-
类 sqlalchemy.dialects.oracle。NCLOB 的
成员-
方法sqlalchemy.dialects.oracle.NCLOB.
__init__(length:intNone=None, collation:strNone=None)¶
继承自sqlalchemy.types.String.__init__
String
的方法
创建字符串保持类型。
参数
length¶ – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略桌子
将发布。 某些数据库可能需要length
在 DDL 中使用,如果VARCHAR
不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。
排序规则¶ –
可选,用于 DDL 和 CAST 表达式的列级排序规则。使用 SQLite、MySQL 和 PostgreSQL 支持的 COLLATE 关键字进行渲染。例如:>>> from sqlalchemy import cast, select, String >>> print(select(cast("some string", String(collation="utf8"))))
SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1
注意
在大多数情况下,Unicode
或UnicodeText
数据类型应用于预期存储非 ASCII 数据的Column
。这些数据类型将确保在数据库上使用正确的类型。
-
-
属性sqlalchemy.dialects.oracle..
sqlalchemy.dialects.oracle 的NVARCHAR2¶ NVARCHAR
的别名
-
类 sqlalchemy.dialects.oracle。数字¶
-
类 sqlalchemy.dialects.oracle。长头¶
成员-
方法sqlalchemy.dialects.oracle.LONG.
__init__(length:intNone=None, collation:strNone=None)¶
继承自sqlalchemy.types.String.__init__
String
的方法
创建字符串保持类型。
参数
length¶ – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略桌子
将发布。 某些数据库可能需要length
在 DDL 中使用,如果VARCHAR
不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。
排序规则¶ –
可选,用于 DDL 和 CAST 表达式的列级排序规则。使用 SQLite、MySQL 和 PostgreSQL 支持的 COLLATE 关键字进行渲染。例如:>>> from sqlalchemy import cast, select, String >>> print(select(cast("some string", String(collation="utf8"))))
SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1
注意
在大多数情况下,Unicode
或UnicodeText
数据类型应用于预期存储非 ASCII 数据的Column
。这些数据类型将确保在数据库上使用正确的类型。
-
-
类 sqlalchemy.dialects.oracle。RAW的¶
类签名
类sqlalchemy.dialects.oracle.RAW
(sqlalchemy.types._Binary
)
-
类 sqlalchemy.dialects.oracle。ROWID的¶
Oracle Database ROWID 类型。
在 cast() 或类似工具中使用时,生成 ROWID。
-
类 sqlalchemy.dialects.oracle。时间戳¶ TIMESTAMP
的 Oracle Database 实施,支持其他特定于 Oracle Database 的模式
2.0 版的新Function。
成员-
方法sqlalchemy.dialects.oracle.TIMESTAMP.
__init__(timezone: bool = False, local_timezone: bool = False)¶
构造新的TIMESTAMP。
-
python-oracle数据库¶
通过 python-oracledb 驱动程序支持 Oracle Database 数据库。
数据库接口¶
python-oracledb 的文档和下载信息(如果适用)可从以下位置获得:
https://oracle.github.io/python-oracledb/
连接¶
连接字符串:
oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
描述¶
Python-oracledb 是适用于 Python 的 Oracle 数据库驱动程序。它具有不需要依赖项的默认“瘦”客户端模式,以及使用 Oracle 客户端库的可选“厚”模式。它支持 SQLAlchemy 功能,包括两阶段事务和 Asyncio。
Python-oracle 是重命名、更新的 cx_Oracle 驱动程序。Oracle 不再在 cx_Oracle 命名空间中发布任何版本。
SQLAlchemy oracledb
dialect 在同一方言名称下提供同步和异步实现。根据引擎的创建方式选择正确的版本:
使用oracle+oracledb://
... 调用create_engine()
将自动选择同步版本:from sqlalchemy import create_engine sync_engine = create_engine( "oracle+oracledb://scott:tiger@localhost?service_name=FREEPDB1" )
使用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=FREEPDB1" )
方言的 asyncio 版本也可以使用oracledb_async
后缀:from sqlalchemy.ext.asyncio import create_async_engine asyncio_engine = create_async_engine( "oracle+oracledb_async://scott:tiger@localhost?service_name=FREEPDB1" )
2.0.25 版中的新增功能:添加了对 oracledb 异步版本的支持。
厚模式支持¶
默认情况下,python-oracledb 驱动程序在不需要安装 Oracle 客户端库的 “thin” 模式下运行。该驱动程序还支持“胖”模式,该模式使用 Oracle 客户端库来获取 Oracle Application Continuity 等功能。
要启用厚模式,请调用 oracledb.init_oracle_client()
显式地将参数 thick_mode=True
传递给
create_engine()
中。要将自定义参数传递给
init_oracle_client()
lib_dir
一样,可以传递一个 dict,例如:
engine = sa.create_engine(
"oracle+oracledb://...",
thick_mode={
"lib_dir": "/path/to/oracle/client/lib",
"config_dir": "/path/to/network_config_file_directory",
"driver_name": "my-app : 1.0.0",
},
)
请注意,传递 lib_dir
路径只能在 macOS 或 Windows 上完成。在 Linux 上,它的行为并不像您预期的那样。
另请参阅
python-oracledb 文档启用 python-oracledb 胖模式
连接到 Oracle 数据库¶
python-oracledb 提供了几种指示目标数据库的方法。方言是从一系列不同的 URL 形式翻译而来的。
给定目标数据库的主机名、端口和服务名称,您可以使用 service_name
查询字符串参数在 SQLAlchemy 中进行连接:
engine = create_engine(
"oracle+oracledb://scott:tiger@hostname:port?service_name=myservice"
)
使用 Easy Connect 字符串连接¶
您可以将任何有效的 python-oracledb 连接字符串作为 dsn
键值传递到 create_engine.connect_args
字典中。请参阅 python-oracledb 文档 Oracle Net Services 连接字符串。
例如,要使用 Easy Connect 字符串
具有超时,以防止连接建立在网络
传输到数据库无法在 30 秒内建立,并且还将
保持活动状态时间为 60 秒,以阻止空闲网络连接
由防火墙终止:
e = create_engine(
"oracle+oracledb://@",
connect_args={
"user": "scott",
"password": "tiger",
"dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60",
},
)
Easy Connect 语法在 Oracle Database 的生命周期内得到了增强。查看数据库版本的文档。当前文档位于了解 Easy Connect 命名方法中。
一般语法类似于:
[[protocol:]//]host[:port][/[service_name]][?parameter_name=value{¶meter_name=value}]
请注意,尽管 SQLAlchemy URL 语法 hostname:port/dbname
看起来像 Oracle 的 Easy Connect 语法,但它是不同的。SQLAlchemy 的 URL 需要 dbname
组件的系统标识符 (SID):
engine = create_engine("oracle+oracledb://scott:tiger@hostname:port/sid")
Easy Connect 语法不支持 SID。它使用服务名称,这是连接到 Oracle Database 的首选。
传递 python-oracledb connect 参数¶
其他 python-oracledb 驱动程序连接选项
可以在 connect_args
中传递。例如:
e = create_engine(
"oracle+oracledb://@",
connect_args={
"user": "scott",
"password": "tiger",
"dsn": "hostname:port/myservice",
"events": True,
"mode": oracledb.AUTH_MODE_SYSDBA,
},
)
使用 tnsnames.ora TNS 别名连接¶
如果未提供端口、数据库名称或服务名称,则方言将使用 Oracle Database DSN“连接字符串”。这会将 URL 的 “hostname” 部分作为数据源名称。例如,如果 tnsnames.ora
文件包含 TNS 别名
的 myalias
中,如下所示:
myalias =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orclpdb1)
)
)
当 myalias
为
hostname 部分,而不指定端口、数据库名称或
service_name
:
engine = create_engine("oracle+oracledb://scott:tiger@myalias")
连接到 Oracle Autonomous Database¶
Oracle Autonomous Database 的用户应使用上面显示的 TNS 别名 URL,或者在
create_engine.connect_args
字典中。
如果 Oracle Autonomous Database 配置了双向 TLS(“mTLS”)连接,则需要其他配置,如连接
到 Oracle Cloud Autonomous Databases。综上所述,Thick 模式用户应该在 sqlnet.ora
中适当地设置文件位置和钱包路径:
e = create_engine(
"oracle+oracledb://@",
thick_mode={
# directory containing tnsnames.ora and cwallet.so
"config_dir": "/opt/oracle/wallet_dir",
},
connect_args={
"user": "scott",
"password": "tiger",
"dsn": "mydb_high",
},
)
mTLS 的精简模式用户在创建引擎时应传递相应的目录和 PEM 钱包密码,类似于:
e = create_engine(
"oracle+oracledb://@",
connect_args={
"user": "scott",
"password": "tiger",
"dsn": "mydb_high",
"config_dir": "/opt/oracle/wallet_dir", # directory containing tnsnames.ora
"wallet_location": "/opt/oracle/wallet_dir", # directory containing ewallet.pem
"wallet_password": "top secret", # password for the PEM file
},
)
通常,config_dir
和 wallet_location
是同一目录,即提取 Oracle Autonomous Database wallet zip 文件的位置。请注意,此目录应受到保护。
连接池¶
具有多个并发用户的应用程序应使用连接池。最小大小的连接池也适用于不经常使用连接的长时间运行的单用户应用程序。
python-oracledb 驱动程序提供了自己的连接池实现,可用于代替 SQLAlchemy 的池化功能。驱动程序池支持高可用性功能,例如死连接检测、针对计划内数据库停机的连接耗尽、对 Oracle 应用程序连续性和透明应用程序连续性的支持,并支持数据库驻留连接池 (DRCP)。
要利用 python-oracledb 的池,请使用
create_engine.creator
参数提供一个函数,该函数
返回新连接以及设置
create_engine.pool_class
设置为 NullPool
以禁用 SQLAlchemy 的池化:
import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool
# Uncomment to use the optional python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)
pool = oracledb.create_pool(
user="scott",
password="tiger",
dsn="localhost:1521/freepdb1",
min=1,
max=4,
increment=1,
)
engine = create_engine(
"oracle+oracledb://", creator=pool.acquire, poolclass=NullPool
)
然后,上述引擎可以正常使用。在内部,python-oracledb 处理连接池:
with engine.connect() as conn:
print(conn.scalar(text("select 1 from dual")))
请参阅 python-oracledb 文档以获取 oracledb.create_pool()
了解创建连接池时可以使用的参数。
使用 Oracle Database Resident Connection Pooling (DRCP)¶
使用 Oracle Database 的数据库驻留连接池 (DRCP) 时,
最佳实践是指定 Connection 类和 “Purity”。请参阅
有关 DRCP 的 python-oracledb 文档。例如:
import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool
# Uncomment to use the optional python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)
pool = oracledb.create_pool(
user="scott",
password="tiger",
dsn="localhost:1521/freepdb1",
min=1,
max=4,
increment=1,
cclass="MYCLASS",
purity=oracledb.PURITY_SELF,
)
engine = create_engine(
"oracle+oracledb://", creator=pool.acquire, poolclass=NullPool
)
然后,在 python-oracledb 处理应用程序连接池并且 Oracle Database 还使用 DRCP 的情况下,可以正常使用上述引擎:
with engine.connect() as conn:
print(conn.scalar(text("select 1 from dual")))
如果您希望为不同的连接使用不同的连接类或纯度,请包装 pool.acquire():
import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool
# Uncomment to use python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)
pool = oracledb.create_pool(
user="scott",
password="tiger",
dsn="localhost:1521/freepdb1",
min=1,
max=4,
increment=1,
cclass="MYCLASS",
purity=oracledb.PURITY_SELF,
)
def creator():
return pool.acquire(cclass="MYOTHERCLASS", purity=oracledb.PURITY_NEW)
engine = create_engine(
"oracle+oracledb://", creator=creator, poolclass=NullPool
)
驱动程序之外的 SQLAlchemy oracledb 方言使用的引擎选项¶
还有一些选项由 SQLAlchemy oracledb dialect 本身使用。这些选项总是直接传递给 create_engine(),
例如:
e = create_engine("oracle+oracledb://user:pass@tnsalias", arraysize=500)
oracledb dialect 接受的参数如下:
Unicode 代码¶
与 Python 3 下的所有 DBAPI 一样,所有字符串本质上都是 Unicode 字符串。
确保正确的客户端编码¶
在 python-oracledb 中,用于所有字符数据的编码是 “UTF-8”。
Unicode 特定的 Column 数据类型¶
Core 表达式语言通过使用
Unicode
和 UnicodeText
数据类型。默认情况下,这些类型对应于 VARCHAR2 和 CLOB Oracle Database 数据类型。将这些数据类型与 Unicode 数据一起使用时,预计数据库配置了 Unicode 感知字符集,以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。
如果 Oracle Database 未配置 Unicode 字符集,则有两个选项是使用 NCHAR
和
NCLOB
数据类型,或者传递标志
use_nchar_for_unicode=True
到 create_engine(),
这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 作为 Unicode
/
UnicodeText
数据类型,而不是 VARCHAR/CLOB。
在 1.3 版本发生变更: Unicode
和 UnicodeText
数据类型现在对应于 VARCHAR2
和 CLOB
Oracle Database 数据类型,除非在调用 create_engine()
时将 use_nchar_for_unicode=True
传递给方言。
编码错误¶
对于 Oracle Database 中的数据存在编码断开的异常情况,方言接受一个参数 encoding_errors
,该参数将传递给 Unicode 解码函数,以影响解码错误的处理方式。该值最终由 Python 解码函数使用,并通过 python-oracledb 的 encodingErrors
参数传递
Cursor.var()
以及 SQLAlchemy 自己的解码函数,因为 python-oracledb 方言在不同情况下都使用了两者。
在 1.3.11 版本加入.
使用 setinputsizes 对 python-oracledb 数据绑定进行细粒度控制¶
python-oracle DBAPI 对 DBAPI setinputsizes()
调用的使用有着深刻而根本的依赖。 此呼吁的目的是建立
绑定到 SQL 语句的数据类型,用于传递 Python 值
作为参数。 虽然几乎没有其他 DBAPI 为
setinputsizes()
调用时,python-oracledb DBAPI 在与 Oracle 数据库的交互中严重依赖它,并且在某些情况下,SQLAlchemy 无法确切地知道应该如何绑定数据,因为某些设置可能会导致截然不同的性能特征,同时改变类型强制行为。
强烈建议 oracledb 方言的用户在数据库类型中阅读 python-oracledb 的内置数据类型符号列表
请注意,在某些情况下,在以下情况下,性能可能会显著下降
使用这些类型与不使用。
在 SQLAlchemy 方面,该 DialectEvents.do_setinputsizes()
事件既可用于 setinputsizes 步骤的运行时可见性(例如日志记录),也可用于完全控制 setinputsizes()
在每个语句上的使用方式。
1.2.9 版本中的新功能: 添加了 DialectEvents.setinputsizes()
示例 1 - 记录所有 setinputsizes 调用¶
以下示例说明了如何在将中间值转换为原始 setinputsizes()
之前从 SQLAlchemy 角度记录这些值
parameter 字典。 字典的键是 BindParameter
具有 .key
和 .type
属性的对象:
from sqlalchemy import create_engine, event
engine = create_engine(
"oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
)
@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 的绑定¶
为了提高性能,默认情况下,从 Oracle Database 获取 LOB 数据类型会为 SQLAlchemy 中的 Text
类型设置。可以按如下方式修改此设置:
from sqlalchemy import create_engine, event
from oracledb import CLOB
engine = create_engine(
"oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
)
@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]
LOB 数据类型¶
LOB 数据类型是指 CLOB、NCLOB 和 BLOB 等“大对象”数据类型。Oracle Database 可以有效地将这些数据类型作为单个缓冲区返回。SQLAlchemy 默认使用类型处理程序来执行此作。
要禁用类型处理程序并使用 read()
方法将 LOB 对象作为经典缓冲对象交付,请参数
auto_convert_lobs=False
可以传递给 create_engine()。
RETURNING 支持¶
oracledb dialect 使用 OUT 参数实现 RETURNING。方言完全支持 RETURNING。
两阶段交易支持¶
python-oracledb 完全支持两阶段事务。(精简模式需要 python-oracledb 2.3)。两阶段交易的 API 在 Core 级别通过 Connection.begin_twophase()
和
Session.twophase
用于透明 ORM 使用。
在 2.0.32 版本发生变更: 添加了对两阶段事务的支持
精确数值¶
SQLAlchemy 的数值类型可以像 Python 一样处理接收和返回值
Decimal
对象或 float 对象。当使用 Numeric
对象或子类(如 Float
、DOUBLE_PRECISION
等)时,Numeric.asdecimal
标志确定值是否应在返回时强制转换为 Decimal
,或作为 float 对象返回。在 Oracle Database 下,更复杂的是,如果 “scale” 为零,则 NUMBER
类型也可以表示整数值,因此特定于 Oracle Database 的 NUMBER
类型也考虑到了这一点。
oracledb 方言广泛使用连接和游标级别的“outputtypehandler”可调用对象,以便根据请求强制转换数值。这些可调用对象特定于正在使用的 Numeric
的特定风格,以及不存在 SQLAlchemy 类型对象的情况。在观察到的情况下,Oracle Database 可能会发送有关所返回的数字类型的不完整或不明确的信息,例如,数字类型隐藏在多个子查询级别下的查询。类型处理程序在所有情况下都会尽最大努力做出正确的决策,对于驱动程序可以做出最佳决策的所有情况,都遵循底层 python-oracledb DBAPI。
当不存在键入对象时,例如执行纯 SQL 字符串时,存在默认的“outputtypehandler”,它通常会返回将精度和小数位数指定为 Python Decimal
对象的数值。 自
出于性能原因,禁用此强制转换为十进制,请传递标志
coerce_to_decimal=False
更改为 create_engine():
engine = create_engine(
"oracle+oracledb://scott:tiger@tnsalias", coerce_to_decimal=False
)
coerce_to_decimal
标志仅影响未与 Numeric
关联的纯字符串 SQL 语句的结果
SQLAlchemy 类型(或类似的子类)。
在 1.2 版本发生变更: Oracle 方言的数字处理系统已经过重新设计,以利用更新的驱动程序功能以及更好的 outputtypehandler 集成。
2.0.0 版中的新增功能:添加了对 python-oracledb 驱动程序的支持。
cx_Oracle¶
通过 cx-Oracle 驱动程序支持 Oracle Database 数据库。
数据库接口¶
cx-Oracle 的文档和下载信息(如果适用)可从以下位置获得:
https://oracle.github.io/python-cx_Oracle/
连接¶
连接字符串:
oracle+cx_oracle://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
描述¶
cx_Oracle 是 Oracle Database 的原始驱动程序。它已被 python-oracledb 取代,应该改用 python-oracledb。
DSN 与 Hostname 连接¶
cx_Oracle 提供了几种指示目标数据库的方法。方言是从一系列不同的 URL 形式翻译而来的。
使用 Easy Connect 语法的主机名连接¶
给定目标数据库的主机名、端口和服务名称,例如
从 Oracle Database 的 Easy Connect 语法中,然后使用
service_name
查询字符串参数:
engine = create_engine(
"oracle+cx_oracle://scott:tiger@hostname:port?service_name=myservice&encoding=UTF-8&nencoding=UTF-8"
)
请注意,在 cx_Oracle 8.0 中,encoding 和 nencoding 的默认驱动程序值已更改为“UTF-8”,因此在使用该版本或更高版本时可以省略这些参数。
要使用完整的 Easy Connect 字符串,请将其作为 dsn
密钥值传递到
create_engine.connect_args
字典中:
import cx_Oracle
e = create_engine(
"oracle+cx_oracle://@",
connect_args={
"user": "scott",
"password": "tiger",
"dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60",
},
)
与 tnsnames.ora 或 Oracle Autonomous Database 的连接¶
或者,如果未提供端口、数据库名称或服务名称,则
dialect 将使用 Oracle Database DSN“连接字符串”。 这需要
“hostname” 部分作为数据源名称。 例如,如果
tnsnames.ora
文件包含 myalias
的 TNS 别名,如下所示:
myalias =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orclpdb1)
)
)
当 cx_Oracle myalias
为
hostname 部分,而不指定端口、数据库名称或
service_name
:
engine = create_engine("oracle+cx_oracle://scott:tiger@myalias")
Oracle Autonomous Database 的用户应使用此语法。如果数据库配置为互 TLS (“mTLS”),则还必须配置云钱包,如 cx_Oracle 文档 连接到自变量数据库 中所示。
SID 连接¶
要使用 Oracle Database 过时的系统标识符连接语法,可以在 URL 的“数据库名称”部分中传递 SID:
engine = create_engine(
"oracle+cx_oracle://scott:tiger@hostname:port/dbname"
)
在上面,传递给 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)))'
请注意,尽管 SQLAlchemy 语法 hostname:port/dbname
看起来像 Oracle 的 Easy Connect 语法,但它有所不同。它使用 SID 代替 Easy Connect 所需的服务名称。Easy Connect 语法不支持 SID。
传递 cx_Oracle connect 参数¶
其他连接参数通常可以通过 URL 查询字符串传递;像 SYSDBA
这样的特定符号被拦截并转换为正确的符号:
e = create_engine(
"oracle+cx_oracle://user:pass@dsn?encoding=UTF-8&nencoding=UTF-8&mode=SYSDBA&events=true"
)
在 1.3 版本发生变更: cx_Oracle 方言现在接受所有参数名称
传递到 cx_Oracle DBAPI。 如
是早期的情况,但没有正确记录,则
create_engine.connect_args
参数也接受所有cx_Oracle DBAPI connect 参数。
要在不使用查询字符串的情况下将参数直接传递给 .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 中,编码
和 nencoding
的默认驱动程序值已更改为“UTF-8”,因此在使用该版本或更高版本时可以省略这些参数。
SQLAlchemy 在驱动程序之外cx_Oracle方言使用的选项¶
还有一些选项是 SQLAlchemy cx_oracle dialect 本身使用的。这些选项始终直接传递给 create_engine()
如:
e = create_engine(
"oracle+cx_oracle://user:pass@dsn", coerce_to_decimal=False
)
cx_oracle 方言接受的参数如下:
使用 cx_Oracle SessionPool¶
cx_Oracle 驱动程序提供了自己的连接池实现,可用于代替 SQLAlchemy 的池功能。驱动程序池支持 Oracle 数据库功能,例如死连接检测、针对计划内数据库停机的连接耗尽、对 Oracle 应用程序连续性和透明应用程序连续性的支持,并支持数据库驻留连接池 (DRCP)。
使用驱动程序池可以通过使用
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=1,
max=4,
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 和
应用程序连续性。
请注意,池创建参数 threaded
、encoding
和
n编码
在以后的 cx_Oracle 版本中已弃用。
使用 Oracle Database Resident Connection Pooling (DRCP)¶
使用 Oracle Database 的 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 Database 还使用 DRCP 时,可以正常使用上述引擎:
with engine.connect() as conn:
print(conn.scalar("select 1 from dual"))
Unicode 代码¶
与 Python 3 下的所有 DBAPI 一样,所有字符串本质上都是 Unicode 字符串。但是,在所有情况下,驱动程序都需要显式编码配置。
确保正确的客户端编码¶
为几乎所有 Oracle 数据库相关软件建立客户端编码的长期接受标准是通过 NLS_LANG 环境
变量。 旧版本的 cx_Oracle 使用此环境变量作为
source 的编码配置。 此变量的格式为
Territory_Country.字符集;典型值为
AMERICAN_AMERICA。AL32UTF8
。cx_Oracle版本 8 及更高版本默认使用字符集 “UTF-8”,并忽略 NLS_LANG 的字符集组件。
cx_Oracle 驱动程序还支持一种编程替代方案,即将 encoding
和 nencoding
参数直接传递给其 .connect()
功能。 这些可以出现在 URL 中,如下所示:
engine = create_engine(
"oracle+cx_oracle://scott:tiger@tnsalias?encoding=UTF-8&nencoding=UTF-8"
)
有关 encoding
和 nencoding
参数的含义,请
咨询
字符集和国家语言支持 (NLS)。
另请参阅
字符集和本地语言支持 (NLS)
- 在 cx_Oracle 文档中。
Unicode 特定的 Column 数据类型¶
Core 表达式语言通过使用
Unicode
和 UnicodeText
数据类型。默认情况下,这些类型对应于 VARCHAR2 和 CLOB Oracle Database 数据类型。将这些数据类型与 Unicode 数据一起使用时,预计数据库配置了 Unicode 感知字符集,并且 NLS_LANG
环境变量(这适用于旧版本的
cx_Oracle),以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。
如果 Oracle Database 未配置 Unicode 字符集,则有两个选项是使用 NCHAR
和
NCLOB
数据类型,或者传递标志
use_nchar_for_unicode=True
到 create_engine(),
这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 作为 Unicode
/
UnicodeText
数据类型,而不是 VARCHAR/CLOB。
在 1.3 版本发生变更: Unicode
和 UnicodeText
数据类型现在对应于 VARCHAR2
和 CLOB
Oracle Database 数据类型,除非在调用 create_engine()
时将 use_nchar_for_unicode=True
传递给方言。
编码错误¶
对于 Oracle Database 中的数据存在编码断开的异常情况,方言接受一个参数 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 Database 客户端接口的交互中严重依赖它,并且在某些情况下,SQLAlchemy 无法确切地知道应如何绑定数据,因为某些设置可能会导致截然不同的性能特征,同时会改变类型强制行为。
强烈建议 cx_Oracle 方言的用户通读
cx_Oracle 的内置数据类型符号列表位于
https://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 角度记录这些值
parameter 字典。 字典的键是 BindParameter
具有 .key
和 .type
属性的对象:
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]
LOB 数据类型¶
LOB 数据类型是指 CLOB、NCLOB 和 BLOB 等“大对象”数据类型。cx_Oracle 的现代版本针对这些数据类型进行了优化,以便作为单个缓冲区提供。因此,SQLAlchemy 默认使用这些较新的类型处理程序。
要禁用较新的类型处理程序,并使用 read()
方法将 LOB 对象作为经典缓冲对象交付,参数
auto_convert_lobs=False
可以传递给 create_engine(),
这只会在引擎范围内发生。
RETURNING 支持¶
cx_Oracle 方言使用 OUT 参数实现 RETURNING。方言完全支持 RETURNING。
不支持两阶段交易¶
由于驱动程序支持不佳,cx_Oracle 不支持两阶段事务。但是,较新的 python-oracledb 方言确实支持两阶段事务。
精确数值¶
SQLAlchemy 的数值类型可以像 Python 一样处理接收和返回值
Decimal
对象或 float 对象。当使用 Numeric
对象或子类(如 Float
、DOUBLE_PRECISION
等)时,Numeric.asdecimal
标志确定值是否应在返回时强制转换为 Decimal
,或作为 float 对象返回。在 Oracle Database 下,更复杂的是,如果 “scale” 为零,则 NUMBER
类型也可以表示整数值,因此特定于 Oracle Database 的 NUMBER
类型也考虑到了这一点。
cx_Oracle dialect 广泛使用连接和游标级别的 “outputtypehandler” 可调用对象,以便根据请求强制转换数值。这些可调用对象特定于正在使用的 Numeric
的特定风格,以及不存在 SQLAlchemy 类型对象的情况。在观察到的情况下,Oracle Database 可能会发送有关所返回的数字类型的不完整或不明确的信息,例如,数字类型隐藏在多个子查询级别下的查询。类型处理程序在所有情况下都会尽最大努力做出正确的决策,对于驱动程序可以做出最佳决策的所有情况,都遵循基础 cx_Oracle DBAPI。
当不存在键入对象时,例如执行纯 SQL 字符串时,存在默认的“outputtypehandler”,它通常会返回将精度和小数位数指定为 Python Decimal
对象的数值。 自
出于性能原因,禁用此强制转换为十进制,请传递标志
coerce_to_decimal=False
更改为 create_engine():
engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)
coerce_to_decimal
标志仅影响未与 Numeric
关联的纯字符串 SQL 语句的结果
SQLAlchemy 类型(或类似的子类)。
在 1.2 版本发生变更: cx_Oracle 的数字处理系统已经过重新设计,以利用更新的 cx_Oracle 功能以及 outputtypehandler 的更好集成。