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
相关产品推荐
相关产品推荐

