1. 概述
在这个简短的教程中,我们将探讨如何解决Hibernate的QueryException: "named parameter not bound"
问题。
首先,我们会解释异常背后的主要原因,然后演示如何重现它,最后学习如何修复。
2. 理解异常
在寻求解决方案之前,让我们先理解这个异常及其堆栈跟踪的含义。
简单来说,当Hibernate在将Hibernate查询转换为SQL时遇到语法错误,它会抛出QueryException
来表示错误。因此,堆栈跟踪中的"named parameter not bound"意味着Hibernate无法绑定查询中的一个指定的命名参数。
通常,命名参数前缀为冒号(:),后面跟着一个实际值的占位符,需要在执行查询前设置:
SELECT p FROM Person p WHERE p.firstName = :firstName;
我们异常的一个常见原因是,在Hibernate查询中忘记为命名参数分配值。
3. 复现异常
现在我们知道导致异常的原因,让我们通过一个实际例子深入了解一下如何复现它。
首先,考虑一下Person
实体类:
@Entity
public class Person {
@Id
private int id;
private String firstName;
private String lastName;
// standard getters and setters
}
在这里,@Entity
注解表示我们的类映射数据库中的一个表,而@Id
表示id
属性代表主键。
现在,我们创建一个带有命名参数的Hibernate查询,并假装忘记为参数设置值:
@Test
void whenNotSettingValueToNamedParameter_thenThrowQueryException() {
Exception exception = assertThrows(QueryException.class, () -> {
Query<Person> query = session.createQuery("FROM Person p WHERE p.firstName = :firstName", Person.class);
query.list();
});
String expectedMessage = "Named parameter not bound";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
}
如我们所见,测试用例由于QueryException
: "named parameter not bound" 失败。原因在于Hibernate对命名参数firstName
一无所知,期望在执行查询前设置这个参数。
4. 修复异常
避免QueryException
的方法是在执行查询前为命名参数分配一个值。可以使用setParameter()
方法:
@Test
void whenSettingValueToNamedParameter_thenDoNotThrowQueryException() {
Query<Person> query = session.createQuery("FROM Person p WHERE p.firstName = :firstName", Person.class);
query.setParameter("firstName", "Azhrioun");
assertNotNull(query.list());
}
如上所示,测试用例成功通过。**setParameter()
调用告诉Hibernate在执行查询时使用哪个值作为我们的命名参数。**
5. 总结
在这篇短文中,我们解释了Hibernate抛出QueryException: "named parameter not bound"
的原因。接着,我们通过实际示例展示了如何重现异常以及如何修复它。
如往常一样,所有示例的完整源代码可在GitHub上找到:https://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate-exceptions。