甲骨文公司

优质
小牛编辑
134浏览
2023-12-01

Support for the Oracle database.

The following table summarizes current support levels for database release versions.

支持的Oracle版本

The following dialect/DBAPI options are available. Please refer to individual DBAPI sections for connect information.

自动增量行为

通常假定包含整数主键的SQLAlchemy表对象具有“自动递增”行为,这意味着它们可以在插入时生成自己的主键值。对于在Oracle中使用,有两个选项可用,即使用标识列(仅限Oracle 12及更高版本)或序列与列的关联。

指定生成为标识(Oracle 12及更高版本)

从版本12开始,Oracle可以使用 Identity 要指定自动递增行为:

t = Table('mytable', metadata,
    Column('id', Integer, Identity(start=3), primary_key=True),
    Column(...), ...
)

上面的创建表 Table 对象为:

CREATE TABLE mytable (
    id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3),
    ...,
    PRIMARY KEY (id)
)

这个 Identity 对象支持许多选项来控制列的“自动递增”行为,如起始值、递增值等。除了标准选项外,Oracle还支持设置 Identity.alwaysNone 要使用默认的生成模式,在DDL中呈现为IDENTITY。它还支持设置 Identity.on_nullTrue 将ON NULL与“默认”标识列一起指定。

使用序列(所有Oracle版本)

旧版本的Oracle没有“autoincrement”特性,SQLAlchemy依赖序列来生成这些值。对于较旧的Oracle版本, 必须始终显式指定序列才能启用自动增量 . 这与大多数文档示例不同,这些文档示例假定使用具有自动增量功能的数据库。要指定序列,请使用传递给列构造的sqlachemy.schema.sequence对象::

t = Table('mytable', metadata,
      Column('id', Integer, Sequence('id_seq'), primary_key=True),
      Column(...), ...
)

使用表反射时也需要此步骤,即AUTLOAD_WITH=ENGINE::

t = Table('mytable', metadata,
      Column('id', Integer, Sequence('id_seq'), primary_key=True),
      autoload_with=engine
)

在 1.4 版更改: 补充 Identity 在a中构造 Column 指定自动递增列的选项。

事务隔离级别/自动提交

Oracle数据库支持“READ COMMITTED”和“SERIALIZABLE”隔离模式。CX_ORACLE方言也支持AUTOCOMMIT隔离级别。

使用每个连接执行选项进行设置:

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

READ COMMITTEDSERIALIZABLE ,Oracle方言使用以下命令在会话级别设置级别 ALTER SESSION ,当连接返回到连接池时,它将恢复为其默认设置。

的有效值 isolation_level 包括:

  • READ COMMITTED

  • AUTOCOMMIT

  • SERIALIZABLE

注解

的实现 Connection.get_isolation_level() 由Oracle方言实现的方法必须使用Oracle LOCAL_TRANSACTION_ID函数强制启动事务;否则没有任何级别通常是可读的。

此外, Connection.get_isolation_level() 方法将引发异常,如果 v$transaction 由于权限或其他原因,视图不可用,这在Oracle安装中很常见。

CX_ORACLE方言尝试调用 Connection.get_isolation_level() 当方言首次连接到数据库以获取“默认”隔离级别时,调用。此缺省级别是必需的,以便在使用临时修改连接后可以在连接上重置该级别 Connection.execution_options() 方法。在常见情况下, Connection.get_isolation_level() 方法引发异常,原因是 v$transaction 由于不可读以及任何其他与数据库相关的故障,该级别被假定为“已提交读取”。对于此初始首次连接条件不会发出警告,因为预计这将是Oracle数据库的常见限制。

1.3.16 新版功能: 向cx_oracle方言添加了对AUTOCOMMIT的支持以及默认隔离级别的概念

1.3.21 新版功能: 添加了对SERIALIZABLE以及隔离级别实时读取的支持。

在 1.3.22 版更改: 在Oracle安装中常见的由于v$TRANSACTION视图上的权限而导致默认隔离级别无法读取的情况下,默认隔离级别被硬编码为“READ COMMITTED”,这是1.3.21之前的行为。

参见

设置事务隔离级别,包括DBAPI Autocommit

标识符大小写

在Oracle中,数据字典使用大写文本表示所有不区分大小写的标识符名称。另一方面,SQLAlchemy认为所有小写标识符名称都不区分大小写。在模式级通信期间,Oracle方言将所有不区分大小写的标识符转换为这两种格式,例如表和索引的反射。在sqlAlchemy端使用大写名称表示区分大小写的标识符,sqlAlchemy将引用该名称-这将导致与从Oracle接收的数据字典数据不匹配,因此,除非标识符名称真正创建为区分大小写(即使用带引号的名称),否则所有小写名称都应在sqlAlchemy上使用。一边。

最大标识符长度

自Oracle Server 12.2版起,Oracle已更改默认的最大标识符长度。在这个版本之前,长度是30,对于12.2及更高版本,现在是128。此更改会影响生成的SQL标签名称区域中的SQLAlchemy以及约束名称的生成,尤其是在中描述的约束命名约定功能的情况下 配置约束命名约定 正在被使用。

为了帮助进行此更改和其他更改,Oracle包含了“兼容性”版本的概念,它是一个独立于实际服务器版本的版本号,以帮助迁移Oracle数据库,并且可以在Oracle服务器本身中进行配置。使用此版本检索兼容性 SELECT value FROM v$parameter WHERE name = 'compatible'; . SQLAlchemy Oracle方言负责确定默认的最大标识符长度时,将在第一次连接时尝试使用此查询,以确定服务器的有效兼容性版本,该版本确定服务器允许的最大标识符长度。如果表不可用,则使用服务器版本信息。

从SQLAlchemy 1.4开始,Oracle方言的默认最大标识符长度为128个字符。第一次连接时,将检测到兼容版本,如果兼容版本低于Oracle 12.2版,则最大标识符长度将更改为30个字符。在所有情况下,设置 create_engine.max_identifier_length 参数将绕过此更改,给定的值将按原样使用:

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@oracle122",
    max_identifier_length=30)

在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时,它变为:

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 server 12.2版或更高版本上运行SQLAlchemy 1.4之前版本的应用程序将面临数据库迁移的情况,即希望对以前生成的较短长度的名称“删除约束”。当标识符长度更改而不首先调整索引或约束的名称时,此迁移将失败。强烈建议此类应用程序利用 create_engine.max_identifier_length 为了保持对截断名称生成的控制,并在更改此值时全面检查和测试登台环境中的所有数据库迁移,以确保已减轻此更改的影响。

在 1.4 版更改: Oracle的默认最大标识符长度为128个字符,如果检测到旧版本的Oracle server(兼容版本<12.2),则在第一次连接时将其调整为30个字符。

极限/偏移支撑

直到12c版,Oracle才对LIMIT和OFFSET提供直接支持。为了在从8系列开始的所有广泛使用的Oracle版本中实现这种行为,SQLAlchemy当前使用ROWNUM来实现LIMIT/OFFSET;准确的方法来自https://blogs.oracle.com/oraclemagazine/on-rownum-and-limiting-results.

当前只有一个选项可以影响其行为:

  • 默认情况下不使用“FIRST_ROWS()”优化关键字。要启用此优化指令的使用,请指定 optimize_limits=Truecreate_engine() .

在 1.4 版更改: Oracle方言使用“后编译”方案呈现限制/偏移整数值,该方案在将语句传递给游标执行之前直接呈现整数。这个 use_binds_for_limits 旗帜不再有效。

参见

新的“后编译”绑定参数用于Oracle、SQL Server中的限制/偏移 .

支持更改行号策略,其中包括一个使用 row_number() 窗口函数以及使用oracle12c“FETCH FIRST N ROW/OFFSET N ROWS”关键字的函数可能会在将来的版本中添加。

返回支持

Oracle数据库支持有限的返回形式,以便从insert、update和delete语句中检索匹配行的结果集。Oracle的返回..in to语法只支持返回一行,因为它依赖out参数才能运行。此外,受支持的DBAPI还有进一步的限制(请参见 返回支持

SQLAlchemy的“隐式返回”功能通常在Oracle后端启用,它使用在insert中返回,有时还使用update语句来获取新生成的主键值和其他SQL默认值和表达式。默认情况下,“隐式返回”通常只获取单个 nextval(some_seq) 嵌入到insert中的表达式,以便在insert语句中增加序列并同时返回值。要全面禁用此功能,请指定 implicit_returning=Falsecreate_engine() ::

engine = create_engine("oracle://scott:tiger@dsn",
                       implicit_returning=False)

隐式返回也可以作为表选项逐个表禁用:

# Core Table
my_table = Table("my_table", metadata, ..., implicit_returning=False)


# declarative
class MyClass(Base):
    __tablename__ = 'my_table'
    __table_args__ = {"implicit_returning": False}

参见

返回支持 -对隐式返回的其他cx_Oracle特定限制。

更新层叠时

Oracle没有原生更新时级联功能。https://asktom.oracle.com/tkyte/update_cascade/index.html上提供了基于触发器的解决方案。

使用SQLAlchemy ORM时,ORM手动发出级联更新的能力有限-使用“deferrable=true,initially='deferred'”关键字参数指定foreignkey对象,并在每个关系()上指定“passive_updates=false”。

Oracle 8兼容性

当检测到Oracle 8时,方言在内部将自身配置为以下行为:

  • “使用”ansi标志设置为false。这样做的效果是将所有连接短语转换为WHERE子句,如果是左外部连接,则使用Oracle的(+)运算符。

  • Unicode 使用-varchar2和clob。这是因为这些类型在Oracle8上似乎不能正常工作,即使它们是可用的。这个 NVARCHARNCLOB 类型将始终生成nvarchar2和nclob。

  • 当使用cx_oracle时,“本机Unicode”模式被禁用,即sqlAlchemy在作为绑定参数传入之前将所有python unicode对象编码为“string”。

同义词/dblink反射

当对表对象使用反射时,方言可以通过传递标志来选择性地搜索由同义词表示的表,无论是在本地模式还是远程模式中,还是通过dblink访问的表。 oracle_resolve_synonyms=True 作为关键字参数 Table 结构:

some_table = Table('some_table', autoload_with=some_engine,
                            oracle_resolve_synonyms=True)

设置此标志时,给定的名称(例如 some_table 将不仅仅在 ALL_TABLES 视图,但也在 ALL_SYNONYMS 查看此名称是否实际上是其他名称的同义词。如果同义词位于并引用dblink,则Oracle方言知道如何使用dblink语法(例如 @dblink

oracle_resolve_synonyms 在接受反射参数的地方接受,包括 MetaData.reflect()Inspector.get_columns() .

如果同义词未使用,则应禁用此标志。

约束反射

Oracle方言可以返回有关外键、唯一和检查约束以及表上索引的信息。

有关这些约束的原始信息可以使用 Inspector.get_foreign_keys()Inspector.get_unique_constraints()Inspector.get_check_constraints()Inspector.get_indexes() .

在 1.2 版更改: Oracle方言现在可以反映唯一和检查约束。

使用反射时 Table 水平 Table 还将包括这些约束。

注意以下注意事项:

  • 当使用 Inspector.get_check_constraints() 方法,Oracle为指定“not null”的列生成一个特殊的“is not null”约束。这个约束是 not 默认情况下返回;要包含“is not null”约束,请传递标志 include_all=True ::

    from sqlalchemy import create_engine, inspect
    
    engine = create_engine("oracle+cx_oracle://s:t@dsn")
    inspector = inspect(engine)
    all_check_constraints = inspector.get_check_constraints(
        "some_table", include_all=True)
  • 在大多数情况下,当反映 Table ,唯一约束将 not 可作为 UniqueConstraint 对象,因为在大多数情况下,Oracle使用唯一索引来镜像唯一约束(当两个或多个唯一约束表示同一列时似乎是例外); Table 而是用 Indexunique=True 标志集。

  • Oracle为表的主键创建隐式索引;此索引是 排除 从所有索引结果。

  • 为索引反映的列列表将不包括以sys_nc开头的列名称。

带有系统/系统辅助表空间的表名

这个 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://scott:tiger@xe",
  exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"])

1.1 新版功能.

日期时间兼容性

Oracle没有已知的数据类型 DATETIME 相反,它只有 DATE ,它实际上可以存储日期和时间值。因此,Oracle方言提供了 DATE 它是 DateTime . 此类型没有特殊行为,并且仅作为此类型的“标记”存在;此外,当数据库列被反映并且该类型被报告为 DATE ,时间支持 DATE 使用类型。

在 0.9.4 版更改: 补充 DATE 子类 DateTime . 这是一个更改,因为以前的版本将反映 DATE 列为 DATE ,哪个子类 Date . 这里唯一的意义是,对于正在检查列类型的方案,这些列用于特殊的Python翻译或用于将模式迁移到其他数据库后端。

Oracle表选项

create table短语与Oracle一起支持以下选项 Table 构建:

  • ON COMMIT ::

    Table(
        "some_table", metadata, ...,
        prefixes=['GLOBAL TEMPORARY'], oracle_on_commit='PRESERVE ROWS')

1.0.0 新版功能.

  • COMPRESS ::

     Table('mytable', metadata, Column('data', String(32)),
         oracle_compress=True)
    
     Table('mytable', metadata, Column('data', String(32)),
         oracle_compress=6)
    
    The ``oracle_compress`` parameter accepts either an integer compression
    level, or ``True`` to use the default compression level.

1.0.0 新版功能.

Oracle特定索引选项

位图索引

您可以指定 oracle_bitmap 创建位图索引而不是B树索引的参数:

Index('my_index', my_table.c.data, oracle_bitmap=True)

位图索引不能是唯一的,也不能压缩。SQLAlchemy不会检查这样的限制,只有数据库会检查。

1.0.0 新版功能.

索引压缩

对于包含大量重复值的索引,Oracle具有更高效的存储模式。使用 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 使用默认值(非唯一索引的所有列,唯一索引的最后一列除外)。

1.0.0 新版功能.

Oracle数据类型

与所有的sqlAlchemy方言一样,已知对Oracle有效的所有大写类型都可以从顶级方言导入,无论它们是否源自 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或具有Oracle特定构造参数的类型如下:

Object NameDescription

BFILE

DATE

提供Oracle日期类型。

DOUBLE_PRECISION

INTERVAL

LONG

NCLOB

NUMBER

RAW

class sqlalchemy.dialects.oracle.BFILE(length=None)

Support for the Oracle database via the cx-Oracle driver.

DBAPI

Documentation and download information (if applicable) for cx-Oracle is available at: https://oracle.github.io/python-cx_Oracle/

Connecting

Connect String:

oracle+cx_oracle://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]

DSN与主机名连接

CX_ORACLE提供了几种指示目标数据库的方法。该方言从一系列不同的URL形式翻译而来。

使用Easy Connect语法的主机名连接

给定目标Oracle数据库的主机名、端口和服务名,例如来自Oracle的 Easy Connect syntax ,然后在SQLAlChemy中使用 service_name 查询字符串参数::

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

这个 full Easy Connect syntax 不受支持。相反,请使用 tnsnames.ora 文件并使用DSN连接。

与tnsnames.ora或Oracle云的连接

或者,如果没有端口、数据库名称或 service_name 则方言将使用Oracle DSN“连接字符串”。这将URL的“hostname”部分作为数据源名称。例如,如果 tnsnames.ora 文件包含一个 Net Service Namemyalias 详情如下:

myalias =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orclpdb1)
    )
  )

CX_ORACLE方言在以下情况下连接到此数据库服务 myalias 是URL的主机名部分,不指定端口、数据库名称或 service_name ::

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

Oracle Cloud的用户应使用此语法,并按照CX_ORACLE文档中所示配置云Wallet Connecting to Autononmous Databases

SID连接

要使用Oracle过时的SID连接语法,可以在URL的“数据库名”部分传递SID,如下所示:

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

传递cxu Oracle connect参数

附加的连接参数通常可以通过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参数。

将参数直接传递给 .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
    }
)

请注意,的默认值为 encodingnencoding 在CX_ORACLE 8.0中更改为“UTF-8”,因此在使用该版本或更高版本时可以省略这些参数。

SQLAlchemy cx_Oracle方言在驱动程序之外使用的选项

还有一些选项被sqlacalchemy cx_Oracle方言本身所使用。这些选项总是直接传递给 create_engine() ,例如:

e = create_engine(
    "oracle+cx_oracle://user:pass@dsn", coerce_to_unicode=False)

cx_Oracle方言接受的参数如下:

  • arraysize -在光标上设置cx_oracle.arraysize值,默认值为50。对于cx_oracle,此设置非常重要,因为lob对象的内容只能在“活动”行中读取(例如,在一批50行中)。

  • auto_convert_lobs -默认为true;请参见 目标对象 .

  • coerce_to_unicode -见 统一码 细节。

  • coerce_to_decimal -见 精确数字 细节。

  • encoding_errors -见 编码错误 细节。

使用CX_Oracle SessionPool

CX_ORACLE库提供了自己的连接池实现,可以用来代替SQLAlChemy的池功能。这可以通过使用 create_engine.creator 参数提供返回新连接的函数,以及设置 create_engine.pool_classNullPool 要禁用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://", creator=pool.acquire, poolclass=NullPool)

然后,在CX_ORACLE的池处理连接池的情况下,可以正常使用上述引擎::

with engine.connect() as conn:
    print(conn.scalar("select 1 FROM dual"))

除了为多用户应用程序提供可扩展的解决方案外,CX_ORACLE会话池还支持一些Oracle功能,如DRCP和 Application Continuity

使用Oracle数据库驻留连接池(DRCP)

在使用Oracle的 DRCP 最佳实践是在从SessionPool获取连接时传递连接类和“纯度”。请参阅 cx_Oracle DRCP documentation

这可以通过包装来实现 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://", creator=creator, poolclass=NullPool)

然后,在CX_ORACLE处理会话池并且Oracle数据库另外使用DRCP::的情况下,可以正常使用上述引擎

with engine.connect() as conn:
    print(conn.scalar("select 1 FROM dual"))

统一码

与python3下的所有dbapi一样,所有字符串本质上都是Unicode字符串。在python2下,cx峈Oracle还直接支持Python Unicode对象。但是,在所有情况下,驱动程序都需要显式的编码配置。

确保正确的客户端编码

为几乎所有与Oracle相关的软件建立客户端编码的长期接受的标准是通过 NLS_LANG 环境变量。与大多数其他Oracle驱动程序一样,cxU Oracle将使用此环境变量作为其编码配置的源。此变量的格式是特殊的;典型的值是 AMERICAN_AMERICA.AL32UTF8 .

除了支持Oracle U pass的编程驱动程序之外,还有一种可选的方法 encodingnencoding 直接将参数 .connect() 功能。这些可以在URL中显示,如下所示:

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

关于 encodingnencoding 参数,请参考 Characters Sets and National Language Support (NLS) .

参见

Characters Sets and National Language Support (NLS) -在cx_Oracle文档中。

Unicode特定的列数据类型

核心表达式语言通过使用 UnicodeUnicodeText 数据类型。默认情况下,这些类型对应于VARCHAR2和CLOB Oracle数据类型。当将这些数据类型与Unicode数据一起使用时,Oracle数据库应该配置有一个支持Unicode的字符集,并且 NLS_LANG 环境变量被适当地设置,以便varchar2和clob数据类型能够容纳数据。

如果Oracle数据库未配置Unicode字符集,则两个选项将使用 NCHARNCLOB 显式的数据类型,或传递标志 use_nchar_for_unicode=Truecreate_engine() ,这将导致sqlAlchemy方言将nchar/nclob用于 Unicode / UnicodeText 数据类型,而不是varchar/clob。

在 1.3 版更改: 这个 UnicodeUnicodeText 数据类型现在对应于 VARCHAR2CLOB Oracle数据类型,除非 use_nchar_for_unicode=Truecreate_engine() 被称为。

python2下结果行的Unicode强制

当获取包含字符串的结果集时,在python 3下,cx_Oracle DBAPI将所有字符串作为python unicode对象返回,因为python 3只有unicode字符串类型。对于从varchar2、char、clob、nchar、nclob等数据类型中提取的数据,会发生这种情况。为了在python 2下提供交叉兼容性,sqlachemy cx_oracle方言也会将unicode转换添加到python 2下的字符串数据中。历史上,这使用了由cx_oracle提供但被发现没有性能的转换器;sqlAlchemy自己的转换器用于python 2下的字符串到unicode转换。要禁用varchar2、char和clob的python 2 unicode转换,标志 coerce_to_unicode=False 可以传递给 create_engine() .

在 1.3 版更改: 在python 2下,默认情况下,Unicode转换应用于所有字符串值。这个 coerce_to_unicode 现在默认为true,可以设置为false以禁用以varchar2/char/clob数据形式传递的字符串的Unicode强制。

编码错误

对于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方言的用户为 强烈鼓励 在https://cx-oracle.readthedocs.io/en/latest/api_manual/module.html#database-types.上阅读CX_ORACLE的内置数据类型符号列表请注意,在某些情况下,使用这些类型与不使用这些类型相比,性能可能会显著降低,特别是在指定 cx_Oracle.CLOB

在炼金术方面, DialectEvents.do_setinputsizes() 事件既可用于setinputsizes步骤的运行时可见性(例如日志记录),也可用于完全控制 setinputsizes() 按语句使用。

1.2.9 新版功能: 补充 DialectEvents.setinputsizes()

示例1-记录所有setinputsizes调用

下面的示例说明如何在将中间值转换为原始值之前,从SQLAlchemy的角度记录它们。 setinputsizes() 参数字典。字典的关键是 BindParameter 具有 .key 和A .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的所有绑定

这个 CLOB cx_oracle中的数据类型会产生很大的性能开销,但是默认情况下会为 Text 在sqlacalchemy 1.2系列中键入。此设置可以修改如下:

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]

返回支持

cx_Oracle方言实现使用out参数返回。方言支持完全返回,但建议使用cx_oracle 6以获得完全支持。

目标对象

cx_oracle使用cx_oracle.lob对象返回Oracle LOB。sqlAlchemy将这些转换为字符串,以便二进制类型的接口与其他后端的接口一致,后者发生在cx_Oracle OutputTypeHandler中。

cx_Oracle在版本6之前将要求在读取新批行之前读取lob对象,这由 cursor.arraysize . 从6系列开始,此限制已解除。不过,由于sqlacalchemy预先读取这些LOB,所以无论如何都可以避免这个问题。

要禁用方言的自动“read()”功能,标志 auto_convert_lobs=False 可传递给 create_engine() . 在cx-oracle 5系列中,关闭此标志意味着如果在提取过时的lob对象时不读取它,则有可能读取该对象。使用cx_Oracle 6,可以解决此问题。

在 1.2 版更改: LOB处理系统在内部被大大简化以使用outputtypehanders,不再使用备用的“缓冲”结果集对象。

不支持两阶段事务

两阶段交易是 不支持 在cx_Oracle下,由于驱动程序支持不佳。从cx_oracle 6.0b1开始,两阶段事务的接口已更改为更直接地传递到底层OCI层,自动化程度更低。支持此系统的附加逻辑未在SQLAlchemy中实现。

精确数字

sqlAlchemy的numeric类型可以像python那样处理接收和返回值 Decimal 对象或浮动对象。当A Numeric 对象或子类,如 FloatDOUBLE_PRECISION 等正在使用中, Numeric.asdecimal 标志确定是否应将值强制为 Decimal 返回时,或作为浮动对象返回。为了使甲骨文下的事情更加复杂,甲骨文的 NUMBER 如果“scale”为零,类型还可以表示整数值,因此Oracle特定 NUMBER 类型也考虑到这一点。

cx-oracle方言广泛使用连接级和光标级的“outputtypehander”可调用文件,以便按要求强制使用数值。这些可调用物是特定于 Numeric 在使用中,以及如果不存在任何SQLAlchemy类型对象。在观察到的情况下,Oracle可能会发送有关返回的数字类型的不完整或不明确的信息,例如,将数字类型隐藏在多个级别的子查询下的查询。类型处理程序在所有情况下都尽其所能做出正确的决策,对于驱动程序能够做出最佳决策的所有情况,都遵从底层的cx_Oracle DBAPI。

当没有输入对象时,如执行普通的SQL字符串时,会出现一个默认的“outputTypeHandler”,它通常会返回指定精度和比例为python的数值。 Decimal 物体。若要出于性能原因禁用强制小数,请传递标志 coerce_to_decimal=Falsecreate_engine() ::

engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)

这个 coerce_to_decimal 标志仅影响纯字符串SQL语句的结果,否则这些语句与 Numeric SQLAlChemy类型(或此类类型的子类)。

在 1.2 版更改: cx_-oracle的数字处理系统已经重新设计,以利用新的cx_-oracle功能以及更好地集成输出类型处理程序。