我有两张表A
和B
。
在表B
中创建新行后,我需要在表ForeignKey
(带A
引用)中创建一些行。但是如果我在事件监听器中遇到异常,我需要在监听器内对已执行的代码进行回滚。我该怎么办?
例如:
class A(db.Model):
__tablename__ = 'a'
id = Column(BigInteger, primary_key=True)
...
class B(db.Model):
__tablename__ = 'b'
id = Column(BigInteger, primary_key=True)
a_id = Column(BigInteger, ForeignKey('a.id'), nullable=False, index=True)
...
@event.listens_for(A, 'after_insert')
def after_insert_listener(mapper, connection, target):
transaction = connection.begin()
try:
...
connection.execute(B.__table__.insert(), a_id=target.id, ...)
transaction.commit()
...
except Exception as e:
# need rollback here if i got exception inside my code
transaction.rollback()
接下来,在我的代码中,我有类似的东西:
a = A(some_field='foo')
db.session.add(a)
db.session.commit()
此代码将我引导至ResourceClosedError: This Connection is closed
(这是我在侦听器中关闭conn时)或InvalidRequestError: This transaction is inactive
请帮帮我,我做错了什么?我认为使用这段代码,我将获得嵌套事务,但据我所知,只有一个事务从session.commit()
执行到侦听器结束。
有关after_insert侦听器的一些信息: http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.MapperEvents.after_insert
如果它可以有所作为,我使用Flask-SqlAlchemy
扩展名。
答案 0 :(得分:0)
除非你在after_insert_listener中提供的示例代码不好,否则你的方法是错误的:而是使用一个监听器来插入B
个实例,只需让sqlalchemy
通过定义来处理这个问题。 A
和B
之间的relationship
:
class A(db.Model):
__tablename__ = 'a'
id = Column(BigInteger, primary_key=True)
...
b_s = relationship("b", backref="a") # @note: new code
...
a = A(some_field='foo')
b1 = B(some_b_field='some value')
a.b_s.append(b1)
db.session.add(a)
#db.session.add(b1) # @note: no need for this, as b1 will be added
# automatically due to relationship with "a" added above
db.session.commit() # @note: this will insert A and then all Bs
# related to it with correct `a_id`