Hibernate Reactive设置LockMode抛出异常问题求助
问题分析与解决方案
问题原因
你遇到的UnsupportedOperationException是因为Hibernate Reactive对NativeQuery设置OPTIMISTIC_FORCE_INCREMENT锁模式的支持存在局限性:当你通过NativeQuery调用setLockMode时,框架没有正确路由到反应式锁处理逻辑(reactiveOnLock),反而调用了同步版本的onLock方法,而该方法在反应式实现中未被支持,直接抛出异常。
可行的规避方案
方案1:改用JPQL查询替代NativeQuery
Hibernate Reactive对JPQL的锁模式支持更完善,能正确触发反应式锁处理流程。修改你的查询代码如下:
return sessionfactory.withTransaction((session, tx) -> { // 替换NativeQuery为JPQL查询 return session.createQuery("SELECT m FROM Model m", Model.class) .setLockMode(LockMode.OPTIMISTIC_FORCE_INCREMENT) .getResultList() .onItemOrFailure() .transform((existingModels, t) -> { // 原有逻辑不变 if (t != null) { Log.error(t, t); } List<Model> toSave = Lists.newArrayList(); for (Model publish : publishedModels) { boolean exist = false; for (Model existing : existingModels) { if (publish.getName().equals(existing.getName())) { toSave.add(existing); exist = true; } } if (!exist) { publish.setId(UUID.randomUUID()); publish.setRevision(1L); toSave.add(publish); } } Wrap wrap = new Wrap(); wrap.setSession(session); wrap.setModels(toSave); return wrap; }) .chain(wrap -> { return wrap.getSession().persistAll(wrap.getModels().toArray()).invoke(v -> session.flush()); }); });
方案2:手动递增版本号(保留NativeQuery的情况下)
如果业务上必须使用NativeQuery,可以手动模拟OPTIMISTIC_FORCE_INCREMENT的效果——因为该锁的核心是强制更新实体的@Version字段,你只需在查询到实体后手动递增版本号即可:
return sessionfactory.withTransaction((session, tx) -> { return session.createNativeQuery("select * from model", Model.class) .getResultList() .onItemOrFailure() .transform((existingModels, t) -> { if (t != null) { Log.error(t, t); } List<Model> toSave = Lists.newArrayList(); for (Model publish : publishedModels) { boolean exist = false; for (Model existing : existingModels) { if (publish.getName().equals(existing.getName())) { // 手动递增版本号,模拟OPTIMISTIC_FORCE_INCREMENT效果 existing.setRevision(existing.getRevision() + 1); toSave.add(existing); exist = true; } } if (!exist) { publish.setId(UUID.randomUUID()); publish.setRevision(1L); toSave.add(publish); } } Wrap wrap = new Wrap(); wrap.setSession(session); wrap.setModels(toSave); return wrap; }) .chain(wrap -> { return wrap.getSession().persistAll(wrap.getModels().toArray()).invoke(v -> session.flush()); }); });
补充说明
关于你提到的Panache-reactive和smallrye-reactive-messaging的超时/会话未释放问题,通常是因为没有正确管理反应式会话的生命周期——确保所有数据库操作都包裹在withTransaction或withSession的作用域内,避免会话泄漏。改用SessionFactory的方式是可行的,但要注意始终通过框架提供的反应式API(如withTransaction)来获取和管理会话,不要手动持有会话实例。
内容的提问来源于stack exchange,提问作者Nicholas Loke
相关产品推荐
相关产品推荐

