You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Liquibase创建锁表时触发Oracle ORA-12838异常是什么原因?

问题描述

我配置了一套DropWizard服务,设置为应用启动时自动执行所有Liquibase数据库迁移操作。服务首次启动时,我会调用Liquibase::listLocks()输出相关信息,该调用的附加作用是:如果DATABASECHANGELOG和DATABASECHANGELOGLOCK表不存在,会自动完成创建。
某次在新部署的Oracle ATP DB上运行时,上述listLocks调用在创建锁表的过程中抛出了如下错误:

ERROR 2021-07-08 17:59:22,546  [main] com.blah.utils.LiquibaseMigrator: Error listing locks!
liquibase.exception.DatabaseException: ORA-12838: cannot read/modify an object after modifying it in parallel
 [Failed SQL: (12838) INSERT INTO DATABASECHANGELOGLOCK (ID, LOCKED) VALUES (1, 0)]
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:430)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:87)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:159)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:139)
    at liquibase.lockservice.StandardLockService.init(StandardLockService.java:128)
    at liquibase.Liquibase.checkLiquibaseTables(Liquibase.java:1176)
    at liquibase.Liquibase.listLocks(Liquibase.java:1193)
    at com.blah.utils.LiquibaseMigrator.dbLocksExist(LiquibaseMigrator.java:xxx)
    at com.blah.utils.LiquibaseMigratorExecutor.dbLocksExist(LiquibaseMigratorExecutor.java:xxx)
    at com.blah.MyApp.migrateDatabase(MyApp.java:xxx)
    at com.blah.MyApp.run(MyApp.java:xxx)
    at com.blah.MyApp.run(MyApp.java:xxx)
    at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:59)
    at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:98)
    at io.dropwizard.cli.Cli.run(Cli.java:78)
    at io.dropwizard.Application.run(Application.java:94)
    at com.blah.MyApp.main(MyApp.java:xxx)
Caused by: java.sql.SQLException: ORA-12838: cannot read/modify an object after modifying it in parallel

服务抛出该异常后Pod会自动重启,陷入循环报错状态。我手动向锁表中插入了它尝试写入的那条数据后,下一次启动就成功了。
当时运行环境中只有1个Pod在运行,因此我判断该问题和启动竞态条件漏洞无关,但不清楚为什么会出现cannot read/modify an object after modifying it in parallel的错误状态,请问是什么原因导致该异常?

原因解答

异常触发逻辑

Oracle的ORA-12838错误的核心规则是:同一个事务内,如果一个对象被并行DML/DDL修改过,事务提交前不能再对该对象执行任何读写操作。
你遇到的问题完全符合该规则的触发条件:

  • Oracle ATP默认对所有DDL操作启用并行执行特性,CREATE TABLE操作会被判定为并行修改操作
  • 低版本Liquibase的锁表初始化逻辑存在事务时序缺陷:创建DATABASECHANGELOGLOCK表的DDL和后续插入初始化记录的INSERT在同一个事务内执行,INSERT操作触发了Oracle的并行修改后访问限制

手动插入后恢复的原因

你手动插入初始化记录时,是在独立事务内完成操作,执行完成后事务会自动提交。后续应用启动时锁表已经存在,Liquibase不需要再执行建表的DDL操作,直接读取已有的锁表数据即可,不会触发并行修改限制。

规避方案
  • 升级Liquibase到4.6及以上版本,该版本已经修复了锁表初始化的事务时序问题,建表完成后会先提交事务再执行插入操作
  • 暂时无法升级的话,可以在JDBC连接参数中添加parallel_query=false关闭Oracle ATP默认的并行执行特性
  • 也可以提前手动创建DATABASECHANGELOG和DATABASECHANGELOGLOCK两张系统表,避免应用启动时自动执行建表操作

内容的提问来源于stack exchange,提问作者Alex Moore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 00:09:00