【问题标题】:Should I always use 'implicit_returning':False in SQLAlchemy?我应该总是在 SQLAlchemy 中使用 'implicit_returning':False 吗?
【发布时间】:2016-07-06 16:09:18
【问题描述】:

在 SQLAlchemy 中始终使用 'implicit_returning': False 的潜在缺陷是什么?

在处理定义了触发器的 MSSQL 表时,我多次遇到问题,并且由于数据库处于复制状态,因此所有表都有触发器。

我现在不确定到底是什么问题。它与自动递增字段有关 - 可能是因为我正在预取自动递增的值,因此我可以将其插入另一个表中。

如果我没有为表设置'implicit_returning': False,当我尝试插入值时,我会收到以下错误:

DML 语句的目标表不能有任何启用的触发器 如果语句包含没有 INTO 子句的 OUTPUT 子句。

如果为了安全起见,我将__table_args__ = {'implicit_returning': False} 放入所有映射类会怎样?

令我特别沮丧的是,我用于开发和测试的本地数据库不在复制中,也不需要该选项,但生产数据库已复制,因此当我部署更改时,它们有时不起作用。 :)

【问题讨论】:

    标签: python sql-server sqlalchemy


    【解决方案1】:

    您可能已经知道,SQLAlchemy Docs 中描述了您陷入困境的原因如下:

    SQLAlchemy 默认使用OUTPUT INSERTED 来获取新生成的 通过IDENTITY 列或其他服务器端的主键值 默认值。 MS-SQL 不允许使用OUTPUT INSERTED on 有触发器的表。禁用OUTPUT INSERTED 在每个表的基础上,为每个表指定 implicit_returning=False 有触发器的表。

    如果您将 SQLAlchemy 引擎设置为回显 SQL,您将看到默认情况下,它会执行以下操作:

    INSERT INTO [table] (id, ...) OUTPUT inserted.[id] VALUES (...)
    

    但如果你禁用implicit_returning,它会改为:

    INSERT INTO [table] (id, ...) VALUES (...); select scope_identity()
    

    所以问题是,“为以防万一,为所有表禁用 implicit_returning 有什么害处吗?”真的是,“用SCOPE_IDENTITY()代替OUTPUT INSERTED有什么缺点吗?”

    我不是专家,但我的印象是虽然OUTPUT INSERTED 是这些天的首选方法,但SCOPE_IDENTITY() 通常也很好。过去,SQL Server 2008(可能还有更早的版本?)有一个错误,SCOPE_IDENTITY 有时没有返回正确的值,但我听说现在已经修复(see this question for more detail)。 (另一方面,@@IDENTITYIDENT_CURRENT() 等其他技术仍然很危险,因为它们可能会在极端情况下返回错误的值。有关更多详细信息,请参阅同一页面上的 this answer 和其他技术。)

    OUTPUT INSERTED 仍然具有的最大优势在于,它可以适用于通过单个 INSERT 语句插入多行的情况。这是你用 SQLAlchemy 做的事情吗?应该不会吧?所以没关系。

    请注意,如果您必须为许多表禁用 implicit_returning,您可以通过为它创建一个 mixin(以及您希望所有表继承的任何其他列和属性)来避免一些样板:

    class AutoincTriggerMixin():
        __table_args__ = {
            'implicit_returning': False
        }
    
        id = Column(Integer, primary_key=True, autoincrement=True)
    
    class SomeModel(AutoincTriggerMixin, Base):
        some_column = Column(String(1000))
        ...
    

    有关详细信息,请参阅this page in the SQLALchemy documentation。作为一个额外的好处,它使哪些表涉及触发器更加明显。

    【讨论】:

      猜你喜欢
      • 2012-01-10
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-17
      • 2011-05-03
      • 2010-11-05
      • 1970-01-01
      相关资源
      最近更新 更多