HQL查询含特殊字符用户名报错,转义无效求解决
JPA Query Throws EntityNotFoundException Despite Existing User with Apostrophe in Username
你遇到的这个问题我之前也碰到过类似的情况,咱们一步步来拆解解决:
首先先贴出你的代码和异常信息,方便大家定位问题:
public User findUser(){ User user = null; String userName = "People's Democratic"; String queryString = "SELECT user from User user where user.userName = :userName "; Map<String, Object> param = new HashMap<String, Object>(); param.put("userName", userName); try { final Query query = entityManager.createQuery(queryString); Set<Map.Entry<String, Object>> parameters = param.entrySet(); for (Map.Entry<String, Object> parameter : parameters) { query.setParameter(parameter.getKey(), parameter.getValue()); } user = (User) query.getSingleResult(); } catch (Exception e) { logger.error("Exception in fetching user for the user = "+userName+ " and queryString = "+queryString, e); if (e instanceof NoResultException) { // User not found } } return user; }
执行时抛出的异常:
javax.persistence.EntityNotFoundException : Unable to find com.domain.User with id .....
首先,别再用StringEscapeUtils.escapeSql()了——这是帮倒忙
JPA的参数化查询(就是你用:userName占位符的方式)本身就会自动处理单引号这类特殊字符,完全不需要手动转义。当你调用escapeSql()时,会把People's Democratic转成People''s Democratic,这时候查询的字符串和数据库里的原始值就不匹配了,自然查不到数据。第一步必须删掉这个转义操作。
为什么会抛出EntityNotFoundException而非预期的NoResultException?
正常来说,getSingleResult()找不到匹配结果时应该抛NoResultException,而EntityNotFoundException通常是用entityManager.find()根据ID查不到数据时才会抛出的。这里出现这个异常大概率有两种可能:
- 你的JPA提供商(比如Hibernate)在某些场景下把
NoResultException包装成了EntityNotFoundException; - 你的
User实体存在延迟加载的关联对象,当查询返回的用户实体被隐式访问时,关联对象找不到触发了这个异常(不过看你的查询是直接查User本身,这种可能性较低)。
具体解决步骤
- 移除SQL转义代码:直接使用原始的
userName值作为参数,不要做任何手动转义。 - 调整异常捕获逻辑:把
EntityNotFoundException也加入捕获分支,确保能正确处理找不到用户的情况:catch (Exception e) { logger.error("Exception in fetching user for the user = "+userName+ " and queryString = "+queryString, e); if (e instanceof NoResultException || e instanceof EntityNotFoundException) { // User not found user = null; } } - 开启SQL日志验证查询:配置JPA的SQL日志,查看实际执行的SQL和参数值,确认参数是否正确传递。比如Hibernate可以在配置文件里添加:
这样你就能看到生成的完整SQL,以及实际传入的参数值,确认是否和数据库里的用户名完全一致。# 开启SQL日志并格式化 hibernate.show_sql=true hibernate.format_sql=true - 验证数据库中的数据:仔细核对数据库里的用户名——包括大小写、空格、单引号的类型(是半角
'还是全角’),这些细微差异都会导致查询失败。 - 换用更安全的
getResultList():如果getSingleResult()的异常逻辑太麻烦,可以改用getResultList()处理结果:
这种方式既不会因为找不到结果抛异常,也能处理结果过多的情况。List<User> results = query.getResultList(); user = results.isEmpty() ? null : results.get(0);
内容的提问来源于stack exchange,提问作者Harshal
相关产品推荐
相关产品推荐

