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

JPA中getSingleResult()与setMaxResults(1)触发NonUniqueResultException的解决方法

嘿,我来帮你理清这个问题~

首先得纠正一个认知:JPA里的getSingleResult()并不是“最多返回一条记录”,而是严格要求查询结果只能是0条或者1条——如果结果集里有超过1条记录,它就会直接抛出NonUniqueResultException,这是JPA规范明确规定的行为,也是你遇到这两个异常的核心原因。

接下来针对你的场景,给几个实用的解决方案:


1. 复用你已经写好的自定义getSingleResult()方法

你自己已经实现了一个非常靠谱的工具方法,它先通过query.setMaxResults(1)限制返回结果数量,再从结果列表里取第一条(没有就返回null),完美避开了JPA原生方法的严格校验。

只需要把你getSspIndRowLockVal方法里的这一行:

DBProc_CalcSSPSettingsPrBean sspIndRowLock = em.createQuery(rowLockQry).getSingleResult();

改成调用自定义方法:

Query query = em.createQuery(rowLockQry);
DBProc_CalcSSPSettingsPrBean sspIndRowLock = getSingleResult(query);

这样不管数据库里有多少条匹配记录,都会只取第一条,不会再抛出NonUniqueResultException。


2. 捕获NonUniqueResultException并处理

如果你不想修改调用逻辑,也可以在catch块里专门捕获这个异常,手动处理多结果的情况:

public DBProc_CalcSSPSettingsPrBean getSspIndRowLockVal(String custAcctNbr) {
    try {
        LOGGER.debug("Entering AccountDaoImpl: getSspIndRowLockValgetSspIndRowLockVal");
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<DBProc_CalcSSPSettingsPrBean> rowLockQry = cb
                .createQuery(DBProc_CalcSSPSettingsPrBean.class);
        Root<PsfsPaAcctSspTb> root = rowLockQry.from(PsfsPaAcctSspTb.class);
        Join<PsfsPaAcctSspTb, PsfsAcctSspTb> acctSspTb = root
                .join("psfsAcctSspTbs");
        Join<PsfsAcctSspTb, PsfsCustAcctTb> custAcct = acctSspTb
                .join("psfsCustAcctTb");
        rowLockQry.multiselect(acctSspTb.get("indRowLock"));
        rowLockQry
                .where(cb.equal(custAcct.get("nbrCustAcct"), custAcctNbr));
        return em.createQuery(rowLockQry).getSingleResult();
    } catch (NoResultException nre) {
        LOGGER.debug("Exit AccountDaoImpl: getSspIndRowLockVal");
        return null;
    } catch (NonUniqueResultException nure) {
        // 遇到多结果时,取第一条返回
        Query query = em.createQuery(rowLockQry);
        query.setMaxResults(1);
        List<DBProc_CalcSSPSettingsPrBean> resultList = query.getResultList();
        LOGGER.debug("Found multiple results for SSP IndRowLock, returning first one");
        return resultList.isEmpty() ? null : resultList.get(0);
    } catch (Exception e) {
        LOGGER.error(
                "Error occurred when fetching IndRowLock Value for SSP", e);
    }
    LOGGER.debug("Exit AccountDaoImpl: getSspIndRowLockVal");
    return null;
}

不过这种方式的复用性不如自定义工具方法,适合临时处理单个场景。


3. 从业务层面优化查询,确保结果唯一

出现多结果的本质是你的关联查询(PsfsPaAcctSspTb → PsfsAcctSspTb → PsfsCustAcctTb)可能对应了多条数据。你可以:

  • 检查数据库中是否存在同一个custAcctNbr对应多条indRowLock记录的情况,清理重复数据;
  • 在查询中添加distinct去重:
    rowLockQry.distinct(true);
    
  • 调整关联条件,比如添加额外的过滤条件(比如最新的记录、特定状态的记录),确保查询逻辑本身只会返回唯一结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:27:33