SqlAlchemy 2.0 中文文档(七十四)(4)https://developer.aliyun.com/article/1562364
关键行为变化 - 核心
自定义运算符的类型行为已经统一
可以使用 Operators.op()
函数动态创建用户定义的运算符。以前,表达式对此类运算符的类型行为不一致,也无法控制。
而在 1.1 版本中,类似以下表达式将产生无返回类型的结果(假设 -%>
是数据库支持的某个特殊运算符):
>>> column("x", types.DateTime).op("-%>")(None).type NullType()
其他类型将使用使用左侧类型作为返回类型的默认行为:
>>> column("x", types.String(50)).op("-%>")(None).type String(length=50)
这些行为大多是偶然发生的,因此行为已与第二种形式保持一致,即默认返回类型与左侧表达式相同:
>>> column("x", types.DateTime).op("-%>")(None).type DateTime()
由于大多数用户定义的运算符往往是“比较”运算符,通常是由 PostgreSQL 定义的许多特殊运算符之一,Operators.op.is_comparison
标志已修复,以遵循其允许返回类型为 Boolean
的文档行为,包括对 ARRAY
和 JSON
:
>>> column("x", types.String(50)).op("-%>", is_comparison=True)(None).type Boolean() >>> column("x", types.ARRAY(types.Integer)).op("-%>", is_comparison=True)(None).type Boolean() >>> column("x", types.JSON()).op("-%>", is_comparison=True)(None).type Boolean()
为了辅助布尔比较运算符,添加了一个新的简写方法 Operators.bool_op()
。应优先使用此方法进行即时布尔运算符:
>>> print(column("x", types.Integer).bool_op("-%>")(5)) x -%> :x_1 ```### `literal_column()` 中的百分号现在有条件地转义 `literal_column` 结构现在根据使用的 DBAPI 是否使用了对百分号敏感的参数样式有条件地转义百分号字符(例如‘format’或‘pyformat’)。 以前,无法生成一个声明单个百分号的 `literal_column` 结构: ```py >>> from sqlalchemy import literal_column >>> print(literal_column("some%symbol")) some%%symbol
对于未设置为使用‘format’或‘pyformat’参数样式的方言,百分号现在不受影响;大多数 MySQL 方言等声明了其中一个参数样式的方言将继续适当转义:
>>> from sqlalchemy import literal_column >>> print(literal_column("some%symbol")) some%symbol >>> from sqlalchemy.dialects import mysql >>> print(literal_column("some%symbol").compile(dialect=mysql.dialect())) some%%symbol
作为这一变化的一部分,使用诸如 ColumnOperators.contains()
、ColumnOperators.startswith()
和 ColumnOperators.endswith()
等运算符时,之前出现的加倍现象也被精细化,只在适当时发生。
#3740 ### 列级别的 COLLATE 关键字现在引用排序规则名称
collate()
和 ColumnOperators.collate()
函数中的一个 bug,用于在语句级别提供临时列排序,已修复,其中一个大小写敏感的名称不会被引用:
stmt = select([mytable.c.x, mytable.c.y]).order_by( mytable.c.somecolumn.collate("fr_FR") )
现在显示为:
SELECT mytable.x, mytable.y, FROM mytable ORDER BY mytable.somecolumn COLLATE "fr_FR"
之前,大小写敏感的名称“fr_FR”不会被引用。目前,手动引用“fr_FR”名称不会被检测到,因此手动引用标识符的应用程序应进行调整。请注意,此更改不会影响类型级别的排序的使用(例如,在表级别上指定在 String
类型上的排序),其中已经应用了引用。
#3785 ### 自定义运算符的输入行为已经保持一致
用户定义的运算符可以使用 Operators.op()
函数动态创建。先前,针对此类运算符的表达式的输入行为是不一致的,也无法控制。
在 1.1 中,例如以下表达式将产生一个没有返回类型的结果(假设 -%>
是数据库支持的某种特殊运算符):
>>> column("x", types.DateTime).op("-%>")(None).type NullType()
其他类型将使用默认行为,即使用左侧类型作为返回类型:
>>> column("x", types.String(50)).op("-%>")(None).type String(length=50)
这些行为大多是偶然发生的,因此行为已与第二种形式保持一致,即默认返回类型与左侧表达式相同:
>>> column("x", types.DateTime).op("-%>")(None).type DateTime()
由于大多数用户定义的运算符倾向于是“比较”运算符,通常是 PostgreSQL 定义的许多特殊运算符之一,因此已修复了 Operators.op.is_comparison
标志,使其遵循其文档化的行为,即在所有情况下允许返回类型为 Boolean
,包括对于 ARRAY
和 JSON
:
>>> column("x", types.String(50)).op("-%>", is_comparison=True)(None).type Boolean() >>> column("x", types.ARRAY(types.Integer)).op("-%>", is_comparison=True)(None).type Boolean() >>> column("x", types.JSON()).op("-%>", is_comparison=True)(None).type Boolean()
为了辅助布尔比较运算符,添加了一个新的简写方法 Operators.bool_op()
。应优先使用此方法进行即时布尔运算:
>>> print(column("x", types.Integer).bool_op("-%>")(5)) x -%> :x_1
literal_column()
中的百分号现在有条件地转义
literal_column
构造现在有条件地转义百分号字符,取决于正在使用的 DBAPI 是否使用了对百分号敏感的参数样式(例如‘format’或‘pyformat’)。
以前,无法生成一个声明了单个百分号的literal_column
构造:
>>> from sqlalchemy import literal_column >>> print(literal_column("some%symbol")) some%%symbol
对于未设置为使用‘format’或‘pyformat’参数样式的方言,百分号现在不受影响;大多数 MySQL 方言等声明了这些参数样式的方言将继续适当地进行转义:
>>> from sqlalchemy import literal_column >>> print(literal_column("some%symbol")) some%symbol >>> from sqlalchemy.dialects import mysql >>> print(literal_column("some%symbol").compile(dialect=mysql.dialect())) some%%symbol
作为这一变化的一部分,使用ColumnOperators.contains()
、ColumnOperators.startswith()
和ColumnOperators.endswith()
等操作符时,之前出现的加倍现象也被优化为仅在适当时发生。
列级别的 COLLATE 关键字现在引用了排序规则名称
修复了collate()
和ColumnOperators.collate()
函数中的一个错误,用于在语句级别提供临时列排序规则,其中一个区分大小写的名称将不会被引用:
stmt = select([mytable.c.x, mytable.c.y]).order_by( mytable.c.somecolumn.collate("fr_FR") )
现在呈现为:
SELECT mytable.x, mytable.y, FROM mytable ORDER BY mytable.somecolumn COLLATE "fr_FR"
以前,区分大小写的名称“fr_FR”将不会被引用。目前,不会检测手动引用“fr_FR”名称,因此手动引用标识符的应用程序应进行调整。请注意,此更改不影响在类型级别使用排序规则(例如在数据类型上指定的String
在表级别),其中已经应用了引用。
方言改进和变更 - PostgreSQL
支持批处理模式 / 快速执行助手
psycopg2 的 cursor.executemany()
方法被认为性能较差,特别是在 INSERT 语句中。为了缓解这一问题,psycopg2 添加了快速执行助手,通过批量发送多个 DML 语句来减少服务器往返次数。SQLAlchemy 1.2 现在包括对这些助手的支持,可以在Engine
使用 cursor.executemany()
对多个参数集合执行语句时透明地使用。该功能默认关闭,可以通过在 create_engine()
上使用 use_batch_mode
参数来启用:
engine = create_engine( "postgresql+psycopg2://scott:tiger@host/dbname", use_batch_mode=True )
目前该功能被视为实验性质,但可能在未来的版本中默认开启。
另请参阅
Psycopg2 快速执行助手
#4109 ### 支持 INTERVAL 中字段规范的支持,包括完整反射
PostgreSQL 的 INTERVAL 数据类型中的“fields”规范允许指定要存储的间隔的哪些字段,包括“YEAR”、“MONTH”、“YEAR TO MONTH”等值。INTERVAL
数据类型现在允许指定这些值:
from sqlalchemy.dialects.postgresql import INTERVAL Table("my_table", metadata, Column("some_interval", INTERVAL(fields="DAY TO SECOND")))
此外,所有 INTERVAL 数据类型现在都可以独立于存在的“fields”规范进行反射;数据类型本身的“fields”参数也将存在:
>>> inspect(engine).get_columns("my_table") [{'comment': None, 'name': u'some_interval', 'nullable': True, 'default': None, 'autoincrement': False, 'type': INTERVAL(fields=u'day to second')}]
#3959 ### 支持批处理模式 / 快速执行助手
psycopg2 的 cursor.executemany()
方法被认为性能较差,特别是在 INSERT 语句中。为了缓解这一问题,psycopg2 添加了快速执行助手,通过批量发送多个 DML 语句来减少服务器往返次数。SQLAlchemy 1.2 现在包括对这些助手的支持,可以在Engine
使用 cursor.executemany()
对多个参数集合执行语句时透明地使用。该功能默认关闭,可以通过在 create_engine()
上使用 use_batch_mode
参数来启用:
engine = create_engine( "postgresql+psycopg2://scott:tiger@host/dbname", use_batch_mode=True )
目前该功能被视为实验性质,但可能在未来的版本中默认开启。
另请参阅
Psycopg2 快速执行助手
支持 INTERVAL 中字段规范的支持,包括完整反射
PostgreSQL 的 INTERVAL 数据类型中的“fields”指定符允许指定要存储的间隔的哪些字段,包括“YEAR”、“MONTH”、“YEAR TO MONTH”等值。INTERVAL
数据类型现在允许指定这些值:
from sqlalchemy.dialects.postgresql import INTERVAL Table("my_table", metadata, Column("some_interval", INTERVAL(fields="DAY TO SECOND")))
此外,现在可以独立于“fields”指定符反映所有 INTERVAL 数据类型;数据类型本身的“fields”参数也将存在:
>>> inspect(engine).get_columns("my_table") [{'comment': None, 'name': u'some_interval', 'nullable': True, 'default': None, 'autoincrement': False, 'type': INTERVAL(fields=u'day to second')}]
方言改进和变更 - MySQL
支持 INSERT…ON DUPLICATE KEY UPDATE
MySQL 支持的 INSERT
的 ON DUPLICATE KEY UPDATE
子句现在可以使用 MySQL 特定版本的 Insert
对象来支持,通过 sqlalchemy.dialects.mysql.dml.insert()
。这个 Insert
子类添加了一个新方法 Insert.on_duplicate_key_update()
,实现了 MySQL 的语法:
from sqlalchemy.dialects.mysql import insert insert_stmt = insert(my_table).values(id="some_id", data="some data to insert") on_conflict_stmt = insert_stmt.on_duplicate_key_update( data=insert_stmt.inserted.data, status="U" ) conn.execute(on_conflict_stmt)
以上内容将呈现为:
INSERT INTO my_table (id, data) VALUES (:id, :data) ON DUPLICATE KEY UPDATE data=VALUES(data), status=:status_1
另请参阅
INSERT…ON DUPLICATE KEY UPDATE (Upsert)
#4009 ### 支持 INSERT…ON DUPLICATE KEY UPDATE
MySQL 支持的 INSERT
的 ON DUPLICATE KEY UPDATE
子句现在可以使用 MySQL 特定版本的 Insert
对象来支持,通过 sqlalchemy.dialects.mysql.dml.insert()
。这个 Insert
子类添加了一个新方法 Insert.on_duplicate_key_update()
,实现了 MySQL 的语法:
from sqlalchemy.dialects.mysql import insert insert_stmt = insert(my_table).values(id="some_id", data="some data to insert") on_conflict_stmt = insert_stmt.on_duplicate_key_update( data=insert_stmt.inserted.data, status="U" ) conn.execute(on_conflict_stmt)
以上内容将呈现为:
INSERT INTO my_table (id, data) VALUES (:id, :data) ON DUPLICATE KEY UPDATE data=VALUES(data), status=:status_1
另请参阅
INSERT…ON DUPLICATE KEY UPDATE (Upsert)
方言改进和变更 - Oracle
cx_Oracle 方言、类型系统的重大重构
随着 cx_Oracle DBAPI 的 6.x 系列的推出,SQLAlchemy 的 cx_Oracle 方言已经重新设计和简化,以利用 cx_Oracle 的最新改进,并放弃了在 cx_Oracle 的 5.x 系列之前更相关的模式的支持。
- 支持的最低 cx_Oracle 版本现在是 5.1.3;推荐使用 5.3 或最新的 6.x 系列。
- 数据类型的处理已经重构。
cursor.setinputsizes()
方法不再用于除 LOB 类型之外的任何数据类型,根据 cx_Oracle 的开发人员的建议。因此,参数auto_setinputsizes
和exclude_setinputsizes
已被弃用,不再起作用。 - 当
coerce_to_decimal
标志设置为 False 时,表示不应发生对具有精度和标度的数值类型进行到Decimal
的强制转换,仅影响未定义类型(例如,没有TypeEngine
对象的普通字符串)的语句。现在,包含Numeric
类型或子类型的 Core 表达式将遵循该类型的十进制强制转换规则。 - “两阶段”事务支持在方言中已经在 cx_Oracle 的 6.x 系列中被删除,现在已完全移除,因为这个功能从未正确工作过,也不太可能被用于生产环境。因此,
allow_twophase
方言标志已被弃用,也不再起作用。 - 修复了涉及 RETURNING 中存在的列键的错误。给定如下语句:
result = conn.execute(table.insert().values(x=5).returning(table.c.a, table.c.b))
- 以前,结果中每行的键是
ret_0
和ret_1
,这些是 cx_Oracle RETURNING 实现内部的标识符。现在,键将是a
和b
,这是其他方言所期望的。 - cx_Oracle 的 LOB 数据类型将返回值表示为
cx_Oracle.LOB
对象,这是一个与游标关联的代理,通过.read()
方法返回最终数据值。在历史上,如果在这些 LOB 对象被消耗之前读取了更多行(特别是在读取了比 cursor.arraysize 值更多的行,导致读取了一批新行),这些 LOB 对象会引发错误“在后续获取后 LOB 变量不再有效”。SQLAlchemy 通过在其类型系统内部自动调用.read()
,以及使用一个特殊的BufferedColumnResultSet
来解决这个问题,该对象将确保在使用cursor.fetchmany()
或cursor.fetchall()
这样的调用时,这些数据被缓冲。
方言现在使用 cx_Oracle outputtypehandler 来处理这些.read()
调用,以便无论获取多少行,它们始终被立即调用,因此不再会发生此错误。因此,BufferedColumnResultSet
的使用,以及一些其他特定于此用例的 CoreResultSet
内部机制已被移除。类型对象也变得更简化,因为它们不再需要处理二进制列结果。
另外,cx_Oracle 6.x 已经删除了此错误发生的条件,因此不再可能发生此错误。在 SQLAlchemy 中,如果很少(如果有的话)使用了auto_convert_lobs=False
选项,并且在 LOB 对象可以被消耗之前读取了更多行,则可能会发生错误。升级到 cx_Oracle 6.x 将解决这个问题。### Oracle 唯一性、检查约束现在已反映。
UNIQUE 和 CHECK 约束现在通过 Inspector.get_unique_constraints()
和 Inspector.get_check_constraints()
反映出来。反映的 Table
对象现在也将包括 CheckConstraint
对象。有关此处行为怪癖的信息,请参阅 约束反射,包括大多数 Table
对象仍不会包括任何 UniqueConstraint
对象,因为这些通常通过 Index
表示。
另请参见
约束反射
#4003 ### Oracle 外键约束名称现在是“名称标准化”
在表反射期间传递给 ForeignKeyConstraint
对象的外键约束名称以及在 Inspector.get_foreign_keys()
方法中将会“名称标准化”,即以小写形式表示以进行大小写不敏感的命名,而不是 Oracle 使用的原始大写格式:
>>> insp.get_indexes("addresses") [{'unique': False, 'column_names': [u'user_id'], 'name': u'address_idx', 'dialect_options': {}}] >>> insp.get_pk_constraint("addresses") {'name': u'pk_cons', 'constrained_columns': [u'id']} >>> insp.get_foreign_keys("addresses") [{'referred_table': u'users', 'referred_columns': [u'id'], 'referred_schema': None, 'name': u'user_id_fk', 'constrained_columns': [u'user_id']}]
以前,外键约束的结果看起来像:
[ { "referred_table": "users", "referred_columns": ["id"], "referred_schema": None, "name": "USER_ID_FK", "constrained_columns": ["user_id"], } ]
上述内容可能会在特别是与 Alembic autogenerate 一起创建问题。
#3276 ### cx_Oracle 方言、类型系统的重大重构
随着 cx_Oracle DBAPI 推出的 6.x 系列,SQLAlchemy 的 cx_Oracle 方言已经进行了重构和简化,以利用 cx_Oracle 的最新改进,并放弃了在 cx_Oracle 5.x 系列之前更相关的模式的支持。
- 支持的最低 cx_Oracle 版本现在是 5.1.3;建议使用 5.3 或最新的 6.x 系列。
- 数据类型的处理已经重构。
cursor.setinputsizes()
方法现在仅用于 LOB 类型,根据 cx_Oracle 的开发人员的建议。因此,参数auto_setinputsizes
和exclude_setinputsizes
已被弃用,不再起作用。 - 当设置为 False 时,
coerce_to_decimal
标志表示不应进行具有精度和标度的数字类型到Decimal
的强制转换,仅影响未类型化的(例如,没有TypeEngine
对象的普通字符串)语句。包含Numeric
类型或子类型的 Core 表达式现在将遵循该类型的十进制强制转换规则。 - 方言中的“两阶段”事务支持已经在 cx_Oracle 的 6.x 系列中删除,因为这个功能从未正确工作过,并且不太可能已经投入生产使用。因此,
allow_twophase
方言标志已被弃用,也不再起作用。 - 修复了涉及 RETURNING 的列键存在的错误。给定以下语句:
result = conn.execute(table.insert().values(x=5).returning(table.c.a, table.c.b))
- 以前,结果中每行的键是
ret_0
和ret_1
,这是 cx_Oracle RETURNING 实现的内部标识符。现在,键将是a
和b
,这是其他方言所期望的。 - cx_Oracle 的 LOB 数据类型将返回值表示为
cx_Oracle.LOB
对象,它是一个与游标关联的代理,通过.read()
方法返回最终数据值。历史上,如果在这些 LOB 对象被消耗之前读取了更多的行(具体来说,如果读取的行数超过了 cursor.arraysize 的值,这会导致读取一批新的行),这些 LOB 对象将引发错误“在后续获取后 LOB 变量不再有效”。SQLAlchemy 解决了这个问题,通过在其类型系统中自动调用.read()
来处理这些 LOB,并使用特殊的BufferedColumnResultSet
确保这些数据被缓冲,以防使用了cursor.fetchmany()
或cursor.fetchall()
这样的调用。
方言现在使用 cx_Oracle 的 outputtypehandler 来处理这些.read()
调用,以便无论读取多少行,它们都始终被提前调用,因此不再会发生此错误。因此,已删除了BufferedColumnResultSet
的使用,以及一些特定于此用例的 CoreResultSet
的其他内部内容。由于不再需要处理二进制列结果,类型对象也变得简化了。
另外,cx_Oracle 6.x 已经删除了此错误在任何情况下发生的条件,因此该错误不再可能发生。在 SQLAlchemy 中,该错误可能发生在很少(如果有的话)使用了auto_convert_lobs=False
选项,并且与之前的 cx_Oracle 5.x 系列一起使用,以及在 LOB 对象可以被消耗之前读取了更多行的情况下。升级到 cx_Oracle 6.x 将解决该问题。
Oracle 唯一性、检查约束现在已反映
唯一约束和检查约束现在通过 Inspector.get_unique_constraints()
和 Inspector.get_check_constraints()
反映出来。一个反映的 Table
对象现在也将包括 CheckConstraint
对象。请参阅 Constraint Reflection 中的注意事项,了解这里的行为怪癖,包括大多数 Table
对象仍将不包括任何 UniqueConstraint
对象,因为这些通常通过 Index
表示。
另请参阅
Constraint Reflection
Oracle 外键约束名称现在已经“名称标准化”
在表反射期间传递给 ForeignKeyConstraint
对象以及在 Inspector.get_foreign_keys()
方法内部的外键约束的名称现在将被“名称标准化”,即,以小写形式表示以便于不区分大小写的名称,而不是 Oracle 使用的原始大写格式:
>>> insp.get_indexes("addresses") [{'unique': False, 'column_names': [u'user_id'], 'name': u'address_idx', 'dialect_options': {}}] >>> insp.get_pk_constraint("addresses") {'name': u'pk_cons', 'constrained_columns': [u'id']} >>> insp.get_foreign_keys("addresses") [{'referred_table': u'users', 'referred_columns': [u'id'], 'referred_schema': None, 'name': u'user_id_fk', 'constrained_columns': [u'user_id']}]
以前,外键结果看起来像是:
[ { "referred_table": "users", "referred_columns": ["id"], "referred_schema": None, "name": "USER_ID_FK", "constrained_columns": ["user_id"], } ]
上述情况可能会特别在 Alembic autogenerate 方面造成问题。
方言改进和更改 - SQL Server
支持具有嵌入点的 SQL Server 架构名称
SQL Server 方言有一种行为,即假定带有点的架构名称是“数据库”。“所有者”标识符对,这在表和组件反射操作以及在呈现架构名称的引用时必须在这些单独的组件之间进行拆分,以使这两个符号分别引用。现在可以使用方括号传递架构参数以手动指定此拆分发生的位置,允许包含一个或多个点的数据库和/或所有者名称:
Table("some_table", metadata, Column("q", String(50)), schema="[MyDataBase.dbo]")
上表将考虑“owner”为MyDataBase.dbo
,在呈现时也将被引用,并且“database”为 None。要分别引用数据库名称和所有者,请使用两对括号:
Table( "some_table", metadata, Column("q", String(50)), schema="[MyDataBase.SomeDB].[MyDB.owner]", )
此外,当传递给 SQL Server 方言的“schema”时,现在会尊重quoted_name
构造;如果引号标志为 True,则给定的符号不会在点上拆分,并且将被解释为“owner”。
另请参见
多部分模式名称
支持 AUTOCOMMIT 隔离级别
PyODBC 和 pymssql 方言现在都支持由Connection.execution_options()
设置的“AUTOCOMMIT”隔离级别,这将在 DBAPI 连接对象上建立正确的标志。
支持带有嵌入点的 SQL Server 模式名称
SQL Server 方言具有这样的行为,即假定具有其中的点的模式名称是“数据库”。“所有者”标识符对,这在表和组件反射操作以及在呈现模式名称的引用时必须将这两个符号分开时发生,以便分别引用这两个符号。现在可以使用括号传递模式参数以手动指定此拆分发生的位置,允许数据库和/或所有者名称本身包含一个或多个点:
Table("some_table", metadata, Column("q", String(50)), schema="[MyDataBase.dbo]")
上表将考虑“owner”为MyDataBase.dbo
,在呈现时也将被引用,并且“database”为 None。要分别引用数据库名称和所有者,请使用两对括号:
Table( "some_table", metadata, Column("q", String(50)), schema="[MyDataBase.SomeDB].[MyDB.owner]", )
此外,当传递给 SQL Server 方言的“schema”时,现在会尊重quoted_name
构造;如果引号标志为 True,则给定的符号不会在点上拆分,并且将被解释为“owner”。
另请参见
多部分模式名称
支持 AUTOCOMMIT 隔离级别
PyODBC 和 pymssql 方言现在都支持由Connection.execution_options()
设置的“AUTOCOMMIT”隔离级别,这将在 DBAPI 连接对象上建立正确的标志。
以前,结果中每行的键是 `ret_0` 和 `ret_1`,这是 cx_Oracle RETURNING 实现的内部标识符。现在,键将是 `a` 和 `b`,这是其他方言所期望的。 + cx_Oracle 的 LOB 数据类型将返回值表示为 `cx_Oracle.LOB` 对象,它是一个与游标关联的代理,通过 `.read()` 方法返回最终数据值。历史上,如果在这些 LOB 对象被消耗之前读取了更多的行(具体来说,如果读取的行数超过了 cursor.arraysize 的值,这会导致读取一批新的行),这些 LOB 对象将引发错误“在后续获取后 LOB 变量不再有效”。SQLAlchemy 解决了这个问题,通过在其类型系统中自动调用 `.read()` 来处理这些 LOB,并使用特殊的 `BufferedColumnResultSet` 确保这些数据被缓冲,以防使用了 `cursor.fetchmany()` 或 `cursor.fetchall()` 这样的调用。 方言现在使用 cx_Oracle 的 outputtypehandler 来处理这些 `.read()` 调用,以便无论读取多少行,它们都始终被提前调用,因此不再会发生此错误。因此,已删除了 `BufferedColumnResultSet` 的使用,以及一些特定于此用例的 Core `ResultSet` 的其他内部内容。由于不再需要处理二进制列结果,类型对象也变得简化了。 另外,cx_Oracle 6.x 已经删除了此错误在任何情况下发生的条件,因此该错误不再可能发生。在 SQLAlchemy 中,该错误可能发生在很少(如果有的话)使用了 `auto_convert_lobs=False` 选项,并且与之前的 cx_Oracle 5.x 系列一起使用,以及在 LOB 对象可以被消耗之前读取了更多行的情况下。升级到 cx_Oracle 6.x 将解决该问题。 ### Oracle 唯一性、检查约束现在已反映 唯一约束和检查约束现在通过 `Inspector.get_unique_constraints()` 和 `Inspector.get_check_constraints()` 反映出来。一个反映的 `Table` 对象现在也将包括 `CheckConstraint` 对象。请参阅 Constraint Reflection 中的注意事项,了解这里的行为怪癖,包括大多数 `Table` 对象仍将不包括任何 `UniqueConstraint` 对象,因为这些通常通过 `Index` 表示。 另请参阅 Constraint Reflection [#4003](https://www.sqlalchemy.org/trac/ticket/4003) ### Oracle 外键约束名称现在已经“名称标准化” 在表反射期间传递给 `ForeignKeyConstraint` 对象以及在 `Inspector.get_foreign_keys()` 方法内部的外键约束的名称现在将被“名称标准化”,即,以小写形式表示以便于不区分大小写的名称,而不是 Oracle 使用的原始大写格式: ```py >>> insp.get_indexes("addresses") [{'unique': False, 'column_names': [u'user_id'], 'name': u'address_idx', 'dialect_options': {}}] >>> insp.get_pk_constraint("addresses") {'name': u'pk_cons', 'constrained_columns': [u'id']} >>> insp.get_foreign_keys("addresses") [{'referred_table': u'users', 'referred_columns': [u'id'], 'referred_schema': None, 'name': u'user_id_fk', 'constrained_columns': [u'user_id']}]
以前,外键结果看起来像是:
[ { "referred_table": "users", "referred_columns": ["id"], "referred_schema": None, "name": "USER_ID_FK", "constrained_columns": ["user_id"], } ]
上述情况可能会特别在 Alembic autogenerate 方面造成问题。
方言改进和更改 - SQL Server
支持具有嵌入点的 SQL Server 架构名称
SQL Server 方言有一种行为,即假定带有点的架构名称是“数据库”。“所有者”标识符对,这在表和组件反射操作以及在呈现架构名称的引用时必须在这些单独的组件之间进行拆分,以使这两个符号分别引用。现在可以使用方括号传递架构参数以手动指定此拆分发生的位置,允许包含一个或多个点的数据库和/或所有者名称:
Table("some_table", metadata, Column("q", String(50)), schema="[MyDataBase.dbo]")
上表将考虑“owner”为MyDataBase.dbo
,在呈现时也将被引用,并且“database”为 None。要分别引用数据库名称和所有者,请使用两对括号:
Table( "some_table", metadata, Column("q", String(50)), schema="[MyDataBase.SomeDB].[MyDB.owner]", )
此外,当传递给 SQL Server 方言的“schema”时,现在会尊重quoted_name
构造;如果引号标志为 True,则给定的符号不会在点上拆分,并且将被解释为“owner”。
另请参见
多部分模式名称
支持 AUTOCOMMIT 隔离级别
PyODBC 和 pymssql 方言现在都支持由Connection.execution_options()
设置的“AUTOCOMMIT”隔离级别,这将在 DBAPI 连接对象上建立正确的标志。
支持带有嵌入点的 SQL Server 模式名称
SQL Server 方言具有这样的行为,即假定具有其中的点的模式名称是“数据库”。“所有者”标识符对,这在表和组件反射操作以及在呈现模式名称的引用时必须将这两个符号分开时发生,以便分别引用这两个符号。现在可以使用括号传递模式参数以手动指定此拆分发生的位置,允许数据库和/或所有者名称本身包含一个或多个点:
Table("some_table", metadata, Column("q", String(50)), schema="[MyDataBase.dbo]")
上表将考虑“owner”为MyDataBase.dbo
,在呈现时也将被引用,并且“database”为 None。要分别引用数据库名称和所有者,请使用两对括号:
Table( "some_table", metadata, Column("q", String(50)), schema="[MyDataBase.SomeDB].[MyDB.owner]", )
此外,当传递给 SQL Server 方言的“schema”时,现在会尊重quoted_name
构造;如果引号标志为 True,则给定的符号不会在点上拆分,并且将被解释为“owner”。
另请参见
多部分模式名称
支持 AUTOCOMMIT 隔离级别
PyODBC 和 pymssql 方言现在都支持由Connection.execution_options()
设置的“AUTOCOMMIT”隔离级别,这将在 DBAPI 连接对象上建立正确的标志。