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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 10:50:21