Hibernate调用lock时自动提交数据库变更问题求助
Hey there, let's tackle your Hibernate/JSF issue step by step. First, let's unpack why that lock call is causing unintended database commits, then cover fixes and best practices.
Why the auto-commit happens
Hibernate's Session works with a persistence context (first-level cache) and uses dirty checking by default. Here's the breakdown:
- When you load
myDataObjectinto the Session (either via a previous fetch or initial load), it enters a persistent state. - Even with
LockOptions.NONE, the object stays in the persistent context. Hibernate automatically tracks all changes to persistent objects in the background. - When the Session flushes (this happens automatically on transaction commit, or even during some query executions), Hibernate compares the object's current state to its state when it was first loaded. If there are differences (from JSF page inputs modifying bean properties, for example), it will generate an
UPDATEstatement and commit those changes to the database—no explicitsave()orupdate()needed.
How to prevent unintended commits
Here are a few reliable ways to stop this auto-save behavior:
1. Replace the dirty object with a fresh database copy
Instead of locking the existing (potentially modified) myDataObject, fetch a clean version directly from the database and overwrite your bean's reference:
// Fetch a fresh, unmodified copy from the database MyData freshData = sess.get(MyData.class, myDataObject.getId()); myDataObject = freshData; // Update your bean to use this clean object
This discards the dirty state entirely, so Hibernate won't trigger any updates when the Session flushes.
2. Mark the object as read-only
Tell Hibernate to skip dirty checking for this object explicitly:
Session sess = getCurrentSession(); sess.buildLockRequest(LockOptions.NONE).lock(myDataObject); sess.setReadOnly(myDataObject, true); // Disable change tracking for this object
Once marked as read-only, Hibernate will ignore any changes to myDataObject and won't generate update statements for it.
3. Evict the object from the Session
Remove the object from Hibernate's persistence context, turning it into a detached object (detached objects aren't tracked for changes):
Session sess = getCurrentSession(); sess.buildLockRequest(LockOptions.NONE).lock(myDataObject); sess.evict(myDataObject); // Remove from the persistence context
Just keep in mind: if you need to modify this object later, you'll have to reattach it via merge() or update().
Better practices for your use case
- Shift permission checks earlier: Instead of waiting until save time to block unauthorized changes, validate permissions when the user first accesses the edit page or initiates a modify action. This reduces unnecessary database load and gives users clearer feedback faster.
- Fix the JSF auto-save root cause: Page navigation triggering saves points to a JSF configuration issue. Check:
- Are your managed beans using
@SessionScoped(which retains state across navigation)? Switching to@ViewScopedmight prevent unintended property updates. - Do any form components have
valueChangeListenerorimmediate="true"set, which could trigger partial submits during navigation?
- Are your managed beans using
- Quick note on NonUniqueObjectException: Even though you said it's not the main focus, this usually happens when the Session already contains another instance of the same entity with the same ID. Fix it by using
merge()instead ofsave()/update(), or evict the existing instance from the Session first.
内容的提问来源于stack exchange,提问作者Pere

