文章目录
微信小程序开发者工具控制台报错
{
"timestamp": "2024-12-05T05:41:32.005+0000",
"status": 500,
"error": "Internal Server Error",
"message": "query did not return a unique result: 2; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 2",
"path": "/admin/signIn"
}
检查服务器报错信息
18616239629
2024-12-05 13:41:32.000 INFO 1287 --- [-nio-443-exec-5] c.p.a.c.MyAuthenticationSuccessHandler : 管理员:18616239629 登录成功 登录IP:139.227.122.92
2024-12-05 13:41:32.004 ERROR 1287 --- [-nio-443-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 2; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 2
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:378)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy173.findByAdminIdAndCreatedDateAfter(Unknown Source)
at com.productQualification.user.service.LoginLogService.findByAdminIdToday(LoginLogService.java:24)
at com.productQualification.api.service.LoginLogApiService.save(LoginLogApiService.java:17)
at com.productQualification.api.config.MyAuthenticationSuccessHandler.onAuthenticationSuccess(MyAuthenticationSuccessHandler.java:95)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:326)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:240)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:791)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.NonUniqueResultException: query did not return a unique result: 2
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:128)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1561)
at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getSingleResult(CriteriaQueryTypeQueryAdapter.java:109)
at sun.reflect.GeneratedMethodAccessor322.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:402)
at com.sun.proxy.$Proxy354.getSingleResult(Unknown Source)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:214)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 67 common frames omitted
javax.persistence.NonUniqueResultException 这个错误,是因为我们发送登录请求时 https://api.crossbiog.com/admin/signIn,返回的登录日志结果有两个,所以报错。
从报错中找到查询方法findByAdminIdAndCreatedDateAfter这个很关键
错误原因分析
报错信息提示了一个关键异常:
javax.persistence.NonUniqueResultException: query did not return a unique result: 2
这表明在执行查询时,JPA 期望返回一个唯一结果(即单条记录),但实际返回了 2 条记录。根本原因通常在于查询返回了多于一条数据,而方法只允许返回一个结果。
关键位置
错误栈中相关位置:
at com.productQualification.user.service.LoginLogService.findByAdminIdToday(LoginLogService.java:24)
at com.productQualification.api.service.LoginLogApiService.save(LoginLogApiService.java:17)
at com.productQualification.api.config.MyAuthenticationSuccessHandler.onAuthenticationSuccess(MyAuthenticationSuccessHandler.java:95)
查询方法:
findByAdminIdAndCreatedDateAfter
可能原因
- 数据库中有多条符合条件的记录:查询条件返回了多条记录,但方法如
getSingleResult()
或Optional<T>.orElseThrow()
只期望返回一条。 - 逻辑错误:业务逻辑可能预期不会出现多条结果,但数据问题导致返回了多条。
- 查询方式:
- 使用了
getSingleResult()
,但实际结果集不唯一。 - 可能是通过
findFirst()
、Optional
处理,查询仍返回多条。
- 使用了
解决方法
1. 检查数据库数据
- 确认
findByAdminIdAndCreatedDateAfter
所查询的表中是否有重复数据。 - 使用查询条件
adminId
和createdDate
,手动查询数据库,检查返回的记录是否超过 1 条。
示例 SQL:
SELECT * FROM login_logs WHERE admin_id = '18616239629' AND created_date > '2024-12-05';
2. 修改查询方法
如果业务逻辑允许多条结果,使用 getResultList()
替代 getSingleResult()
。
List<LoginLog> logs = query.getResultList();
if (!logs.isEmpty()) {
return logs.get(0); // 或者按业务需求处理
}
3. 限定查询返回唯一结果
确保查询只返回一条数据,可以加上 LIMIT 1
或调整查询条件:
@Query("SELECT l FROM LoginLog l WHERE l.adminId = :adminId AND l.createdDate > :createdDate ORDER BY l.createdDate DESC")
Optional<LoginLog> findFirstByAdminIdAndCreatedDateAfter(@Param("adminId") String adminId, @Param("createdDate") Date createdDate);
4. 检查业务逻辑
在 LoginLogService
中,确认 findByAdminIdToday
是否处理了返回多条数据的情况。
总结
该错误通常是因为数据不唯一导致的,解决方法是要么确保数据库中的数据唯一,要么修改查询方法使其能处理多条记录。
1、LoginLogRepository
ptional<LoginLog> findByAdminIdAndCreatedDateAfter(Integer adminId, Date date);
2、LoginLogService
public Optional<LoginLog> findByAdminIdToday(Integer adminId) {
Date today = DateUtil.getLocalDate();
return loginLogRepository.findByAdminIdAndCreatedDateAfter(adminId, today);
}
3、LoginLogApiService
public LoginLog save(Integer adminId, String ip) {
Optional<LoginLog> loginLogOptional = loginLogService.findByAdminIdToday(adminId);
return loginLogOptional.orElseGet(() -> loginLogService.save(new LoginLog(adminId, ip)));
}
4、MyAuthenticationSuccessHandler
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
String username = auth.getName();
System.out.println(username);
Admin admin = adminCacheService.findByUsername(username);
//校验域名是否正确
List<Role> roles = roleCacheService.findRolesByAdminId(admin.getId());
String roleName = null;
String introduction = null;
if (!roles.isEmpty()) {
Role role = roles.get(0);
roleName = role.getName();
// introduction = role.getIntroduction();
}
request.getSession().setAttribute(Constants.ADMIN_ID, admin.getId());
request.getSession().setAttribute(Constants.ADMIN_NAME, admin.getUsername());
admin.setPasswordAttemptCount(0);
admin.setLockedDate(null);
admin.setLastLoginTime(new Date());
admin.setStatus(Admin.NORMAL_STATUS);
adminCacheService.save(admin);
String ip = IPUtil.getClientIP(request);
logger.info("管理员:{} 登录成功 登录IP:{}", username, ip);
AdminAdminDTO adminAdminDTO = JSON.parseObject(JSON.toJSONString(admin), AdminAdminDTO.class);
adminAdminDTO.setRole(roleName);
// if (null != appConfig) {
// adminAdminDTO.setLogo(appConfig.getLogo());
// adminAdminDTO.setLogoMin(appConfig.getLogoMin());
// }
// return BaseResult.success(adminAdminDTO);
// User user = (User)auth.getPrincipal();
String token = JwtUtils.createToken(admin.getId().toString(), "admin", username, roleName);
adminAdminDTO.setToken(token);
// adminAdminDTO.setIntroduction(introduction);
loginLogApiService.save(admin.getId(), ip);
adminAdminDTO.setVip(adminService.isSuper(admin.getId()) || subscribeService.isVIP(admin.getId()));
adminAdminDTO.setCopywritingEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 1).isPresent());
adminAdminDTO.setCommunityLinkEditor(adminService.isCommunity(admin.getId()) || copywritingEditorService.findByEditorIdAndType(admin.getId(), 2).isPresent());
adminAdminDTO.setMaterialInspirationer(copywritingEditorService.findByEditorIdAndType(admin.getId(), 3).isPresent());
adminAdminDTO.setIndustryStandardEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 4).isPresent());
adminAdminDTO.setCustomerEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 5).isPresent());
adminAdminDTO.setLogisticsCalculationEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 6).isPresent());
adminAdminDTO.setPromotionRegistrationEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 7).isPresent());
adminAdminDTO.setSynergyEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 8).isPresent());
adminAdminDTO.setExamEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 9).isPresent());
adminAdminDTO.setPageAuditEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 10).isPresent());
adminAdminDTO.setFakeRegistrationEditor(copywritingEditorService.findByEditorIdAndType(admin.getId(), 11).isPresent());
adminAdminDTO.setFakeComparor(fakeConfigService.findByCompareAdminId(admin.getId()).isPresent());
ResponseUtil.out(response, BaseResult.success(adminAdminDTO));
}
我们登录阿里云数据库,查看登录日志
SELECT * FROM `login_log`
WHERE `admin_id` = 75
发现数据库中确实有两条一模一样的登录记录,都在同一时刻,只有ip地址不同,所以返回了两条记录,所以报了上述错误,我们只需要删除一条即可。
SELECT * FROM login_log WHERE admin_id = '75' AND created_date > '2024-12-05'
DELETE FROM login_log WHERE id = 1808;
此时不在报上述错误。