Slick 3.3.3操作DB2自增主键表执行UPDATE报错的解决方案
问题根源
Slick 执行.update(实体对象)时,会默认读取Table类中*投影定义的所有字段生成UPDATE语句的SET子句,你的定义里包含了带O.AutoInc属性的自增主键RECORD_ID,而DB2禁止修改自增主键列,因此抛出SQLCODE=-798错误。
最优解决方案
这里提供两种生产环境常用的方案,均比DELETE+INSERT的实现更安全、性能更好:
方案1:给自增主键标记不可更新(推荐,改动最小)
Slick 3.2及以上版本支持给列添加O.Updatable(false)属性,标记该字段不会出现在默认生成的UPDATE语句中。
仅需修改SomethingTbl的record_id列定义即可:
def record_id: Rep[Long] = column[Long]("RECORD_ID", O.PrimaryKey, O.AutoInc, O.Updatable(false))
修改后原有update方法不需要任何调整,Slick自动生成的UPDATE语句会自动排除RECORD_ID字段,完全符合你的预期。
方案2:手动指定需要更新的字段(灵活可控)
如果仅需更新少量字段,你可以在编写更新逻辑时显式指定要修改的列,完全自主控制SET子句内容:
修改updateSomething方法实现如下:
private def updateSomething(e: SomethingRec): FixedSqlAction[Int, NoStream, Effect.Write] = { someThings .filter(_.record_id === e.record_id) .map(_.status) // 仅选中需要更新的STATUS字段 .update(e.status) // 传入对应新值 }
如果需要同时更新多个字段,调整map和update的参数即可:
// 示例:同时更新STATUS和REMARK两个字段 .map(t => (t.status, t.remark)) .update((e.status, e.remark))
注意事项
- 不推荐使用DELETE+INSERT的替代方案:该方案会额外消耗自增序列号、降低操作性能,并发场景下还可能引发事务一致性问题。
- 两种方案均兼容你当前使用的Slick 3.3.3、Scala 2.12版本,不需要额外升级依赖。
内容的提问来源于stack exchange,提问作者radumanolescu
相关产品推荐
相关产品推荐

