预言机


支持 Oracle Database 数据库。


下表总结了数据库发行版的当前支持级别。


支持的 Oracle 数据库版本


支撑类型


版本


支持的版本

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,
)


在 1.4 版本发生变更: Column 中添加了 Identity 构造,以指定自动递增列的选项。


事务隔离级别 / 自动提交


Oracle Database 支持“READ COMMITTED”和“SERIALIZABLE”隔离模式。python-oracledb 和 cx_Oracle 方言也支持 AUTOCOMMIT 隔离级别。


要使用每个连接的执行选项进行设置,请执行以下作:

connection = engine.connect()
connection = connection.execution_options(isolation_level="AUTOCOMMIT")


对于 READ COMMITTEDSERIALIZABLE,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() 方法,则以下说明适用:


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 时,方言会在内部将自身配置为以下行为:


  • use_ansi 标志设置为 False。这具有将所有 JOIN 短语转换为 WHERE 子句的效果,并且在 LEFT OUTER JOIN 的情况下使用 Oracle 的 (+) 运算符。


  • 使用 Unicode 时,NVARCHAR2 和 NCLOB 数据类型不再生成为 DDL,而是发出 VARCHAR2 和 CLOB。这是因为这些类型似乎在 Oracle 8 上无法正常工作,即使它们可用。NVARCHARNCLOB 类型将始终生成 NVARCHAR2 和 NCLOB。


约束反射


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 约束。


Table 级别使用反射时, 桌子 也将包括这些约束。


请注意以下注意事项:


  • 使用 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() 中。默认情况下,这些作不包括 SYSTEMSYSAUX 表空间。为了改变这一点,可以使用 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 FloatDouble 数据类型是通用数据类型,可解析为给定后端的“最不令人惊讶”的数据类型。对于 Oracle Database,这意味着它们解析为 FLOATDOUBLE 类型:

>>> 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_FLOATBINARY_DOUBLE 来提供实际的 4 字节和 8 字节 FP 值。


SQLAlchemy 使用 BINARY_FLOATBINARY_DOUBLE。使用 FloatDouble 数据类型,同时允许 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 的构造参数的类型如下:


对象名称

描述

BFILE

BINARY_DOUBLE


实施 Oracle BINARY_DOUBLE 数据类型。

BINARY_FLOAT


实现 Oracle BINARY_FLOAT 数据类型。

DATE


提供 Oracle Database DATE 类型。

FLOAT


Oracle 数据库 FLOAT。

INTERVAL

LONG

NCLOB

NUMBER

NVARCHAR2


NVARCHAR 的别名

RAW

ROWID


Oracle Database ROWID 类型。

TIMESTAMP


TIMESTAMP 的 Oracle Database 实施,支持其他特定于 Oracle Database 的模式


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


实施 Oracle BINARY_DOUBLE 数据类型。


此数据类型与 Oracle DOUBLE 数据类型的不同之处在于,它提供真正的 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


实现 Oracle BINARY_FLOAT 数据类型。


此数据类型与 Oracle FLOAT 数据类型的不同之处在于,它提供真正的 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._OracleDateLiteralRendersqlalchemy.types.DateTime


方法 sqlalchemy.dialects.oracle.DATE. __init__timezone bool = False


继承自 sqlalchemy.types.DateTime.__init__ DateTime 的方法


构造新的 DateTime


参数


timezone – 布尔值。 指示 datetime 类型应 启用 Timezone Support(如果 仅限基准日期/时间持有类型。建议在使用此标志时直接使用 TIMESTAMP 数据类型,因为某些数据库包含与支持时区的 TIMESTAMP 数据类型不同的单独通用日期/时间保持类型,例如 Oracle Database。


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=Noneasdecimal=Falsedecimal_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.NativeForEmulatedsqlalchemy.types._AbstractInterval


方法 sqlalchemy.dialects.oracle.INTERVAL. __init__day_precision=second_precision=


构造一个 INTERVAL.


请注意,目前仅支持 DAY TO SECOND 间隔。这是因为在可用的 DBAPI 中缺乏对 YEAR TO MONTH 间隔的支持。


参数

  • day_precision —— 日精度值。这是要为 Day 字段存储的位数。默认为 “2”


  • second_precision —— 第二个精度值。这是要为 Fractional seconds 字段存储的位数。默认为 “6”。


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


    注意


    在大多数情况下,UnicodeUnicodeText 数据类型应用于预期存储非 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


    注意


    在大多数情况下,UnicodeUnicodeText 数据类型应用于预期存储非 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 = Falselocal_timezone: bool = False


构造新的 TIMESTAMP。


参数

  • timezone – 布尔值。指示 TIMESTAMP 类型应使用 Oracle Database 的 TIMESTAMP WITH TIME ZONE 数据类型。


  • local_timezone —— 布尔值。指示 TIMESTAMP 类型应使用 Oracle Database 的 TIMESTAMP WITH LOCAL TIME ZONE 数据类型。


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{&parameter_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_dirwallet_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 接受的参数如下:


  • arraySize - 设置驱动程序 cursor.arraySize 值。它默认为 None,指示应使用驱动程序默认值 100。此设置控制在获取行时缓冲的行数,如果对于返回大量行的查询,如果增加,则可能会对性能产生重大影响。


    在版本 2.0.26 中进行了更改:- 将默认值从 50 更改为 None,以使用驱动程序本身的默认值。


  • auto_convert_lobs - 默认为 True;请参阅 LOB 数据类型


  • coerce_to_decimal - 有关详细信息,请参阅精确数值


  • encoding_errors - 有关详细信息,请参阅编码错误


Unicode 代码¶


与 Python 3 下的所有 DBAPI 一样,所有字符串本质上都是 Unicode 字符串。


确保正确的客户端编码


在 python-oracledb 中,用于所有字符数据的编码是 “UTF-8”。


Unicode 特定的 Column 数据类型


Core 表达式语言通过使用 UnicodeUnicodeText 数据类型。默认情况下,这些类型对应于 VARCHAR2 和 CLOB Oracle Database 数据类型。将这些数据类型与 Unicode 数据一起使用时,预计数据库配置了 Unicode 感知字符集,以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。


如果 Oracle Database 未配置 Unicode 字符集,则有两个选项是使用 NCHARNCLOB 数据类型,或者传递标志 use_nchar_for_unicode=Truecreate_engine(),这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 作为 Unicode / UnicodeText 数据类型,而不是 VARCHAR/CLOB。


在 1.3 版本发生变更: UnicodeUnicodeText 数据类型现在对应于 VARCHAR2CLOB 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 对象或子类(如 FloatDOUBLE_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 方言接受的参数如下:


  • arraysize - 在游标上设置 cx_oracle.arraySize 值;defaults 为 None,指示应使用驱动程序 default(通常值为 100)。此设置控制在获取行时缓冲的行数,并且在修改时可能会对性能产生重大影响。


    在版本 2.0.26 中进行了更改:- 将默认值从 50 更改为 None,以使用驱动程序本身的默认值。


  • auto_convert_lobs - 默认为 True;请参阅 LOB 数据类型


  • coerce_to_decimal - 有关详细信息,请参阅精确数值


  • encoding_errors - 有关详细信息,请参阅编码错误


使用 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 和 应用程序连续性


请注意,池创建参数 threadedencodingn编码在以后的 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 驱动程序还支持一种编程替代方案,即将 encodingnencoding 参数直接传递给其 .connect() 功能。 这些可以出现在 URL 中,如下所示:

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@tnsalias?encoding=UTF-8&nencoding=UTF-8"
)


有关 encodingnencoding 参数的含义,请 咨询 字符集和国家语言支持 (NLS)。


另请参阅


字符集和本地语言支持 (NLS) - 在 cx_Oracle 文档中。


Unicode 特定的 Column 数据类型


Core 表达式语言通过使用 UnicodeUnicodeText 数据类型。默认情况下,这些类型对应于 VARCHAR2 和 CLOB Oracle Database 数据类型。将这些数据类型与 Unicode 数据一起使用时,预计数据库配置了 Unicode 感知字符集,并且 NLS_LANG 环境变量(这适用于旧版本的 cx_Oracle),以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。


如果 Oracle Database 未配置 Unicode 字符集,则有两个选项是使用 NCHARNCLOB 数据类型,或者传递标志 use_nchar_for_unicode=Truecreate_engine(),这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 作为 Unicode / UnicodeText 数据类型,而不是 VARCHAR/CLOB。


在 1.3 版本发生变更: UnicodeUnicodeText 数据类型现在对应于 VARCHAR2CLOB 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 对象或子类(如 FloatDOUBLE_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 的更好集成。