SqlAlchemy 2.0 中文文档(八十一)(4)https://developer.aliyun.com/article/1559916
水平扩展(分片)API
[browser:/sqlalchemy/trunk/examples/sharding/attribute_shard .py]
会话
新的会话创建范例;SessionContext,assignmapper 弃用
是的,整个流程正在用两个配置函数替换。同时使用两者将产生自 0.1 版以来最接近 0.1 版感觉的体验(即,输入最少)。
在定义您的 engine(或任何位置)的地方配置您自己的 Session 类:
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine = create_engine("myengine://") Session = sessionmaker(bind=engine, autoflush=True, transactional=True) # use the new Session() freely sess = Session() sess.save(someobject) sess.flush()
如果需要在会话后配置您的会话,比如说使用引擎,请稍后使用 configure() 添加:
Session.configure(bind=create_engine(...))
所有SessionContext的行为以及assignmapper的query和__init__方法都移至新的scoped_session()函数中,该函数与sessionmaker和create_session()兼容:
from sqlalchemy.orm import scoped_session, sessionmaker Session = scoped_session(sessionmaker(autoflush=True, transactional=True)) Session.configure(bind=engine) u = User(name="wendy") sess = Session() sess.save(u) sess.commit() # Session constructor is thread-locally scoped. Everyone gets the same # Session in the thread when scope="thread". sess2 = Session() assert sess is sess2
当使用线程本地Session时,返回的类已实现了所有Session的接口作为类方法,并且可以使用mapper类方法来使用“assignmapper”的功能。就像旧的objectstore时代一样……。
# "assignmapper"-like functionality available via ScopedSession.mapper Session.mapper(User, users_table) u = User(name="wendy") Session.commit()
会话再次默认使用弱引用
weak_identity_map标志现在默认设置为True在Session上。外部解除引用并超出范围的实例将自动从会话中移除。但是,具有“脏”更改的项目将保持强引用,直到这些更改被刷新,此时对象将恢复为弱引用(这适用于“可变”类型,如可选属性)。将weak_identity_map设置为False将为那些像缓存一样使用会话的人恢复旧的强引用行为。
自动事务会话
正如您可能已经注意到的,我们在Session上调用commit()。标志transactional=True意味着Session始终处于事务中,commit()会永久保存。
自动刷新会话
此外,autoflush=True意味着Session将在每次query之前flush(),以及在调用flush()或commit()时。因此,现在这将起作用:
Session = sessionmaker(bind=engine, autoflush=True, transactional=True) u = User(name="wendy") sess = Session() sess.save(u) # wendy is flushed, comes right back from a query wendy = sess.query(User).filter_by(name="wendy").one()
事务方法移至会话
commit()和rollback(),以及begin()现在直接在Session上。不再需要为任何事情使用SessionTransaction(它仍然在后台运行)。
Session = sessionmaker(autoflush=True, transactional=False) sess = Session() sess.begin() # use the session sess.commit() # commit transaction
与包含引擎级(即非 ORM)事务共享Session很容易:
Session = sessionmaker(autoflush=True, transactional=False) conn = engine.connect() trans = conn.begin() sess = Session(bind=conn) # ... session is transactional # commit the outermost transaction trans.commit()
使用 SAVEPOINT 的嵌套会话事务
在引擎和 ORM 级别可用。迄今为止的 ORM 文档:
www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
两阶段提交会话
在引擎和 ORM 级别可用。迄今为止的 ORM 文档:
www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
新的会话创建范式;SessionContext,assignmapper 已弃用
是的,整个设置正在被两个配置函数替换。同时使用两者将产生自 0.1 版本以来最接近 0.1 版本的感觉(即,键入的数量最少)。
在定义您的engine(或任何地方)时配置自己的Session类:
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine = create_engine("myengine://") Session = sessionmaker(bind=engine, autoflush=True, transactional=True) # use the new Session() freely sess = Session() sess.save(someobject) sess.flush()
如果您需要对会话进行后期配置,比如添加引擎,请稍后使用configure()进行添加:
Session.configure(bind=create_engine(...))
所有SessionContext的行为以及assignmapper的query和__init__方法都移至新的scoped_session()函数中,该函数与sessionmaker和create_session()兼容:
from sqlalchemy.orm import scoped_session, sessionmaker Session = scoped_session(sessionmaker(autoflush=True, transactional=True)) Session.configure(bind=engine) u = User(name="wendy") sess = Session() sess.save(u) sess.commit() # Session constructor is thread-locally scoped. Everyone gets the same # Session in the thread when scope="thread". sess2 = Session() assert sess is sess2
使用线程本地 Session 时,返回的类实现了所有 Session 的接口作为类方法,并且可以使用 mapper 类方法来使用 “assignmapper” 的功能。就像旧的 objectstore 时代一样……。
# "assignmapper"-like functionality available via ScopedSession.mapper Session.mapper(User, users_table) u = User(name="wendy") Session.commit()
会话再次默认为弱引用
weak_identity_map 标志现在默认设置为 True 在 Session 上。外部解除引用并超出范围的实例会自动从会话中移除。但是,具有“脏”更改的项目将保持强引用,直到这些更改被刷新,此时对象将恢复为弱引用(这适用于‘可变’类型,如可选属性)。将 weak_identity_map 设置为 False 可以为那些像缓存一样使用会话的人恢复旧的强引用行为。
自动事务会话
正如您可能已经注意到的,我们在 Session 上调用 commit()。标志 transactional=True 意味着 Session 总是处于事务中,commit() 永久保存。
自动刷新会话
此外,autoflush=True 意味着 Session 在每次 query 之前都会执行 flush(),以及在调用 flush() 或 commit() 时也会执行。所以现在这将起作用:
Session = sessionmaker(bind=engine, autoflush=True, transactional=True) u = User(name="wendy") sess = Session() sess.save(u) # wendy is flushed, comes right back from a query wendy = sess.query(User).filter_by(name="wendy").one()
事务方法移至会话
commit() 和 rollback(),以及 begin() 现在直接在 Session 上。不再需要为任何事情使用 SessionTransaction(它仍然在后台运行)。
Session = sessionmaker(autoflush=True, transactional=False) sess = Session() sess.begin() # use the session sess.commit() # commit transaction
与封闭的引擎级(即非 ORM)事务共享 Session 很容易:
Session = sessionmaker(autoflush=True, transactional=False) conn = engine.connect() trans = conn.begin() sess = Session(bind=conn) # ... session is transactional # commit the outermost transaction trans.commit()
使用 SAVEPOINT 的嵌套会话事务
在引擎和 ORM 层面都可用。迄今为止的 ORM 文档:
www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
两阶段提交会话
在引擎和 ORM 层面都可用。迄今为止的 ORM 文档:
www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
继承
无连接或联合的多态继承
继承的新文档:www.sqlalchemy.org/docs/04 /mappers.html#advdatamapping_mapper_inheritance_joined
使用 get() 时更好的多态行为
在加入表继承层次结构中,所有类都使用基类获得 _instance_key,即 (BaseClass, (1, ), None)。这样,当您对基类进行 get() 查询时,它可以在当前标识映射中定位子类实例,而无需查询数据库。
无连接或联合的多态继承
继承的新文档:www.sqlalchemy.org/docs/04 /mappers.html#advdatamapping_mapper_inheritance_joined
使用 get() 时更好的多态行为
在连接表继承层次结构中,所有类都使用基类获取_instance_key,即(BaseClass, (1, ), None)。这样当你对基类调用get()时,它可以在当前标识映射中定位子类实例,而无需查询数据库。
类型
sqlalchemy.types.TypeDecorator的自定义子类
有一个新 API用于子类化 TypeDecorator。在某些情况下使用 0.3 API 会导致编译错误。
sqlalchemy.types.TypeDecorator的自定义子类
有一个新 API用于子类化 TypeDecorator。在某些情况下使用 0.3 API 会导致编译错误。
SQL 表达式
所有新的、确定性的标签/别名生成
所有“匿名”标签和别名现在都使用简单的<name>_<number>格式。SQL 更容易阅读,并且与计划优化器缓存兼容。只需查看一些教程中的示例:www.sqlalchemy.org/docs/04/ormtutorial.html www.sqlalchemy.org/docs/04/sqlexpression.html
生成式select()构造
这绝对是使用select()的正确方法。查看 htt p://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_transf orm。
新操作系统
SQL 运算符和几乎每个 SQL 关键字现在都被抽象为编译器层。它们现在具有智能行为,并且具有类型/后端感知能力,请参阅:www.sqlalchemy.org/docs/04/sqlexpression.html#sql_operators
所有type关键字参数重命名为type_
就像它所说的:
b = bindparam("foo", type_=String)
in_函数更改为接受序列或可选择项
in_函数现在以其唯一参数接受值序列或可选择的。以前的 API 仍然支持传递值作为位置参数,但现在已过时。这意味着
my_table.select(my_table.c.id.in_(1, 2, 3)) my_table.select(my_table.c.id.in_(*listOfIds))
应更改为
my_table.select(my_table.c.id.in_([1, 2, 3])) my_table.select(my_table.c.id.in_(listOfIds))
所有新的、确定性的标签/别名生成
所有“匿名”标签和别名现在都使用简单的<name>_<number>格式。SQL 更容易阅读,并且与计划优化器缓存兼容。只需查看一些教程中的示例:www.sqlalchemy.org/docs/04/ormtutorial.html www.sqlalchemy.org/docs/04/sqlexpression.html
生成式select()构造
这绝对是使用select()的正确方法。查看 htt p://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_transf orm。
新操作系统
SQL 操作符以及几乎每个 SQL 关键字都现在抽象成了编译器层。它们现在具有智能行为,并且具有类型/后端感知性,请参阅:www.sqlalchemy.org/docs/04/sqlexpression.html#sql_operators
所有 type 关键字参数重命名为 type_
就像它说的那样:
b = bindparam("foo", type_=String)
in_ 函数更改为接受序列或可选择项
in_ 函数现在接受一个值序列或可选择项作为其唯一参数。之前的传递值作为位置参数的 API 仍然有效,但现在已被弃用。这意味着
my_table.select(my_table.c.id.in_(1, 2, 3)) my_table.select(my_table.c.id.in_(*listOfIds))
应更改为
my_table.select(my_table.c.id.in_([1, 2, 3])) my_table.select(my_table.c.id.in_(listOfIds))
模式和反射
MetaData、BoundMetaData、DynamicMetaData…
在 0.3.x 系列中,BoundMetaData 和 DynamicMetaData 已被弃用,而不是 MetaData 和 ThreadLocalMetaData。旧名称已在 0.4 版本中移除。更新很简单:
+-------------------------------------+-------------------------+ |If You Had | Now Use | +=====================================+=========================+ | ``MetaData`` | ``MetaData`` | +-------------------------------------+-------------------------+ | ``BoundMetaData`` | ``MetaData`` | +-------------------------------------+-------------------------+ | ``DynamicMetaData`` (with one | ``MetaData`` | | engine or threadlocal=False) | | +-------------------------------------+-------------------------+ | ``DynamicMetaData`` | ``ThreadLocalMetaData`` | | (with different engines per thread) | | +-------------------------------------+-------------------------+
MetaData 类型中不常用的 name 参数已被移除。ThreadLocalMetaData 构造函数现在不接受任何参数。这两种类型现在可以绑定到一个 Engine 或单个 Connection。
一步多表反射
现在您可以在一次通行中从整个数据库或模式加载表定义并自动创建 Table 对象:
>>> metadata = MetaData(myengine, reflect=True) >>> metadata.tables.keys() ['table_a', 'table_b', 'table_c', '...']
MetaData 还增加了一个 .reflect() 方法,可以更精细地控制加载过程,包括指定要加载的可用表的子集。
MetaData、BoundMetaData、DynamicMetaData…
在 0.3.x 系列中,BoundMetaData 和 DynamicMetaData 已被弃用,而不是 MetaData 和 ThreadLocalMetaData。旧名称已在 0.4 版本中移除。更新很简单:
+-------------------------------------+-------------------------+ |If You Had | Now Use | +=====================================+=========================+ | ``MetaData`` | ``MetaData`` | +-------------------------------------+-------------------------+ | ``BoundMetaData`` | ``MetaData`` | +-------------------------------------+-------------------------+ | ``DynamicMetaData`` (with one | ``MetaData`` | | engine or threadlocal=False) | | +-------------------------------------+-------------------------+ | ``DynamicMetaData`` | ``ThreadLocalMetaData`` | | (with different engines per thread) | | +-------------------------------------+-------------------------+
MetaData 类型中不常用的 name 参数已经被移除。ThreadLocalMetaData 构造函数现在不接受任何参数。这两种类型现在可以绑定到一个 Engine 或单个 Connection。
一步多表反射
现在您可以在一次通行中从整个数据库或模式加载表定义并自动创建 Table 对象:
>>> metadata = MetaData(myengine, reflect=True) >>> metadata.tables.keys() ['table_a', 'table_b', 'table_c', '...']
MetaData 还增加了一个 .reflect() 方法,可以更精细地控制加载过程,包括指定要加载的可用表的子集。
SQL 执行
engine、connectable 和 bind_to 现在都是 bind
Transactions、NestedTransactions 和 TwoPhaseTransactions
连接池事件
当新的 DB-API 连接被创建、检出和重新放回到池中时,连接池现在会触发事件。您可以使用这些事件在新连接上执行会话范围的 SQL 设置语句,例如。
Oracle Engine 修复
在 0.3.11 版本中,Oracle Engine 处理主键的方式存在 bug。这些 bug 可能导致在使用 Oracle Engine 时,那些在其他引擎(如 sqlite)上运行良好的程序失败。在 0.4 版本中,Oracle Engine 已经重做,修复了这些主键问题。
Oracle 的输出参数
result = engine.execute( text( "begin foo(:x, :y, :z); end;", bindparams=[ bindparam("x", Numeric), outparam("y", Numeric), outparam("z", Numeric), ], ), x=5, ) assert result.out_parameters == {"y": 10, "z": 75}
连接绑定的 MetaData、Sessions
MetaData 和 Session 可以明确绑定到一个连接:
conn = engine.connect() sess = create_session(bind=conn)
更快、更可靠的 ResultProxy 对象
engine,connectable 和 bind_to 现在都改为 bind
Transactions,NestedTransactions 和 TwoPhaseTransactions
连接池事件
现在连接池在创建新的 DB-API 连接、检出和检入连接池时会触发事件。您可以利用这些事件在新连接上执行会话范围的 SQL 设置语句,例如。
Oracle 引擎已修复
在 0.3.11 版本中,Oracle 引擎在处理主键时存在 bug。这些 bug 可能导致在使用 Oracle 引擎时,那些在其他引擎(如 sqlite)上正常运行的程序失败。在 0.4 版本中,Oracle 引擎已经重新设计,修复了这些主键问题。
用于 Oracle 的输出参数
result = engine.execute( text( "begin foo(:x, :y, :z); end;", bindparams=[ bindparam("x", Numeric), outparam("y", Numeric), outparam("z", Numeric), ], ), x=5, ) assert result.out_parameters == {"y": 10, "z": 75}
连接绑定的 MetaData,Sessions
MetaData 和 Session 可以显式绑定到连接:
conn = engine.connect() sess = create_session(bind=conn)