逐点分析。
1.
我有一个遗留数据库,需要编写一些数据处理工具。使用Mapper模式(无ORM/ActiveRecord样式),就像使用ActiveRecord一样简单,便于编写查询语句。 它操作着看起来像SQL子句的可组合对象,防止SQL注入攻击。由于对象是“被动”的,所以更具灵活性/一致性:复杂连接的结果是一个命名元组,就像简单选择的结果一样。 不需要关注身份识别,也不会出现具有相同身份的缓存对象。
所有更新都是显式的;不是在其他地方修改状态的“保存”,也没有在 .save()
上运行的钩子等。这使得有效的批量更新变得轻松,而无需担心是否将正确的数据发送到DB中。这在我的情况下都是优点。在一般情况下,“要看情况而定”。例如,我必须手动获取插入后生成的ID。显式运行此查询需要额外的工作。能够在一个查询中完成而不是每个记录一个查询,在我的情况下是巨大的利好。
SQLAlchemy具有分层设计,允许您访问较低级别的“mapper”级别,即使您在较高的ORM级别上声明了某些内容并且通常在其上操作。例如,在Django中,如果/仍然可能存在,则不是那么直截了当。
2.
在这个例子中,“repository”看起来像是在“mapper”之上构建的层级。存储库可以建立在纯DBAPI之上,但Mapper使一些事情变得更简单,例如更美观的参数绑定,结果集的命名元组以及具有可组合,可重用部分的纯SQL包装器。
Mapper还提供了某种程度的数据库独立性。例如,SQL Server和Postgres有不同的字符串拼接方式; Mapper提供了一个统一的接口。
3.
您可以在使用它的地方编写选择语句。如果您在不同的上下文中不断重复使用选择语句,则可以将其放入方法或函数中。大多数选择都只使用一次并现场生成。
SQLAlchemy设计的一个好处是,您可以轻松地存储条件和整个where
子句,并在select/update/delete语句中重用它们。
4.
Question.query.filter_by(text = text).all()
使用隐式事务。db.session.query(Question).filter(Question.text == text).all()
使用显式事务。
显式事务使您在DML上放心。当查询快速更改的数据库并且希望几个相关的选择查看相同的一致状态时,它们对于select
也很重要。
我通常在sessionmaker
周围编写一个微不足道的包装器,并以此方式编写:
with my_database.transaction() as trans:
records = trans.query(...)
...
updated = trans.execute(...).rowcount
当我确定这个代码块不应该运行任何DML时,我使用.readonly_transaction()
,它总是回滚。
在许多情况下,隐式事务是可以接受的。Django允许您使用@transaction.atomic
装饰一个方法,并具有半显式事务控制,在99%的情况下足够了。但有时您需要更细粒度的控制。