交易第二十二条军规



在事务块中涉及的表上存在唯一键约束问题。

关键约束的目的是防止一名球员在团队比赛期间的进球时间内有一个以上的进球或助攻。这很好,没有重复的得分记录,很棒。

然而,如果一支球队选择了错误的进球者或助攻获得者(例如,球员a获得了助攻,但本应获得进球积分),然后想要更新记录,关键约束会阻止更新的发生,因为球员a在更新时,将在同一个进球上同时有进球和助攻。

我应该提到,我使用的是JDBC SQL包装器,所以我不能直接控制生成的SQL。

为了解决这个问题,我决定删除现有的目标并插入,所有这些都在事务块中。同样的交易违反了关键约束。是否可以在同一事务块中删除和插入?生成SQL的代码看起来像:

db.handle withSession { implicit ss: SS =>
ss.withTransaction {
val result = for{
d <- teams.map{id=> model.delete(gameID, id)}
s <- rows.map{x=> model.insert(x)}
} yield s
}
}
if(result.forall(_.isRight)) Right
else { ss.rollback; Left( i18n("not updated") ) }

解决方案是在一个查询中删除整个游戏,或者,如果只有一个团队的统计数据被提交更新(在我们的系统中允许),则删除该团队的目标游戏统计数据。

在完全删除统计数据的情况下,我们有:

db.handle withSession { implicit ss: SS =>
ss.withTransaction {
val result = for{
d <- model.delete(gameID)
s <- rows.map{x=> model.insert(x)}
} yield s
}
}
if(result.forall(_.isRight)) Right
else { ss.rollback; Left( i18n("not updated") ) }

关键是,在存在密钥约束的事务块中,似乎不能执行多个删除查询,然后执行多个插入,以重新填充已删除的数据,否则将因不删除要插入的数据而破坏该密钥约束。

不确定这是否有意义,甚至是否正确;-),但是在单个查询中执行删除确实允许随后的插入执行而不会出现问题。

两全其美,可以保留所需的密钥约束,并执行事务性删除/插入(注意:我不能REPLACE INTO,因为JDBC包装器库不支持它)。

最新更新