执行EntityManager.find()时遇OptimisticLockException求助(DB2+WAS8.0)
先直接拆解核心问题:你看到的OptimisticLockException其实是OpenJPA对DB2底层锁超时错误的包装,根源是DB2返回的SQLCODE=-913,SQLSTATE=57033——这个错误明确表示:你的查询请求要访问的数据库资源(行/表)被其他事务锁住了,且等待锁释放的时间超过了DB2的配置阈值。
下面分步骤给你排查和解决的方案:
1. 先定位持有锁的源头
首先要搞清楚是谁锁住了table_test表中column2='00000' AND column3='000011'的这一行。你可以用DB2的系统视图或者命令工具来排查:
用SQL查询锁信息
执行以下SQL,找出持有锁的应用和事务:
SELECT LOCK_NAME, LOCK_MODE, LOCK_STATUS, TABLE_NAME, APPLICATION_HANDLE, APPLICATION_NAME, AUTHID FROM SYSIBMADM.LOCKS_HELD WHERE TABLE_NAME = 'TABLE_TEST';
结果里的APPLICATION_HANDLE和APPLICATION_NAME会告诉你是哪个应用(比如另一个WAS实例、后台作业)在持有锁。如果是长事务未提交,直接联系对应的业务方终止或者提交事务即可。
用DB2命令行工具
如果有DB2客户端权限,可以执行:
db2pd -locks -db <你的数据库名>
这个命令会输出更详细的锁持有情况,包括锁类型、持有时间等。
2. 调整DB2的锁等待超时时间
如果业务上确实需要更长的锁等待时间(比如某些场景下事务执行本身就慢),可以修改DB2的LOCKTIMEOUT参数:
修改数据库配置
执行以下SQL(替换<你的数据库名>和<超时秒数>,比如设置为120秒):
UPDATE DB CFG FOR <你的数据库名> USING LOCKTIMEOUT <超时秒数>;
然后执行db2 terminate让配置生效(LUW版本的DB2支持在线修改,无需重启数据库,但需要终止当前连接)。
注意:不要把超时设置得过大,否则可能导致大量请求堆积,反而降低系统可用性。
3. 优化应用的事务和查询逻辑
从根源减少锁等待的概率:
- 缩短事务生命周期:不要在事务中执行非数据库操作(比如调用外部API、等待用户输入),尽量把事务控制在最小范围,执行完立即提交/回滚。
- 添加合适的索引:给
table_test的column2和column3创建联合索引,让你的查询更快定位到目标行,减少锁等待的窗口:CREATE INDEX IDX_TABLE_TEST_COL2_COL3 ON TABLE_TEST (COLUMN2, COLUMN3); - 调整读操作的隔离级别:如果这个
EntityManager.find()是只读查询,可以考虑用快照隔离或者读未提交级别,避免被写锁阻塞。在OpenJPA中可以通过以下方式设置:- 全局配置:在
persistence.xml中添加<property name="openjpa.jdbc.TransactionIsolation" value="read-uncommitted"/> - 单个查询设置:
Query query = em.createQuery("SELECT a.column1 FROM table_test a WHERE a.column2 = ? AND a.column3 = ?"); query.setParameter(1, "00000"); query.setParameter(2, "000011"); query.setHint("javax.persistence.lock.timeout", 10000); // 设置10秒超时
- 全局配置:在
4. 检查OpenJPA的乐观锁配置
因为异常被包装成了OptimisticLockException,要确认你的table_test对应的实体类是否配置了乐观锁(比如@Version注解)。如果乐观锁机制和DB2的悲观锁冲突:
- 如果不需要乐观锁,可以直接移除
@Version注解; - 如果需要乐观锁,确保版本字段在每次更新时都会被正确更新,避免因为版本不匹配导致的锁异常。
内容的提问来源于stack exchange,提问作者Kanhu Charan Sahu

