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

JOOQ中结合POJO实现乐观锁及解决映射后update()抛出DataChangedException问题

Solution for Combining POJO Mappings with jOOQ Optimistic Locking

Hey Alexander, let's work through this problem you're facing with jOOQ, POJOs, and optimistic locking. The root issue here is that when you create a new UserRecord from a POJO, jOOQ doesn't populate the internal originals[] array—this array holds the record's state as it was loaded from the database, which is what jOOQ uses to validate optimistic lock checks in update() or store().

Here are a few solid solutions to fix this:


1. Reuse the Original Record (Simplest Approach)

Instead of creating a brand new UserRecord from your modified POJO, merge the POJO's changes back into the original record you fetched from the database. This preserves the originals[] array that jOOQ needs for optimistic locking:

// Fetch the original record with intact originals state
UserRecord userRecord = context.fetchOne(...);
UserPojo userPojo = mapper.toPojo(userRecord);

// Modify the POJO
userPojo.setName("new_name");

// Merge POJO changes back into the original record
mapper.toRecord(userPojo, userRecord); 

// Now store() will trigger optimistic lock checks correctly
userRecord.store();

This works because the original userRecord still has its originals[] field populated from the initial fetch. The store() method will compare the current values (including the version field) against the original state and the database, handling optimistic lock validation as expected.


2. Manually Populate Original Values for New Records

If you absolutely need to create a new UserRecord from the POJO, you can manually set the original optimistic lock field value(s) so jOOQ can perform its check:

UserRecord userRecord = context.fetchOne(...);
UserPojo userPojo = mapper.toPojo(userRecord);
userPojo.setName("new_name");

UserRecord userRecordForSave = context.newRecord(USER, userPojo);

// Set the original version value from the fetched record
userRecordForSave.setOriginal(USER.VERSION, userRecord.getVersion());

// Mark the version field as unchanged (so jOOQ doesn't treat it as a modified value)
userRecordForSave.changed(USER.VERSION, false);

// Now update() will validate the optimistic lock correctly
userRecordForSave.update();

If you're using jOOQ's built-in @Version annotation for optimistic locking, this ensures that jOOQ can compare the original version against the database's current value.


3. Batch Set Original Values (For Multiple Fields)

If you need to preserve original values for more than just the version field, you can copy all original values from the fetched record to the new one:

UserRecord userRecord = context.fetchOne(...);
UserPojo userPojo = mapper.toPojo(userRecord);
userPojo.setName("new_name");

UserRecord userRecordForSave = context.newRecord(USER, userPojo);

// Copy all original values from the fetched record
userRecordForSave.setOriginal(userRecord.originalValues());

// Mark only the fields you modified as changed (e.g., NAME)
userRecordForSave.changed(USER.NAME, true);

// Mark other fields (like VERSION) as unchanged
userRecordForSave.changed(USER.VERSION, false);

userRecordForSave.update();

Key Takeaway

jOOQ's optimistic locking relies on the originals[] array to track the record's state at load time. By either reusing the original record or manually populating the original values in the new record, you can maintain this state while still using your POJO mapping logic.

内容的提问来源于stack exchange,提问作者Alexander Golub

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:27:32