从零开始 Spring Boot 66:JPA 查询参数
图源:简书 (jianshu.com)
JPA 的查询参数分为两种:
- 命名参数(Named Parameters)
- 位置参数(Positional Parameters)
类似于 Python 中的函数的位置参数和指名参数。
本文的示例使用下面的实体类:
@Entity
public class Student {
private static final int MAX_SCORE = 100;
private static final int MIN_SCORE = 0;
public enum Type {
MIDDLE_SCHOOL_STUDENT,
HIGH_SCHOOL_STUDENT,
COLLEGE_STUDENT
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Length(max = 45)
@NotBlank
@NotNull
@Column(unique = true)
private String name;
@NotNull
private Type type;
@NotNull
@Min(MIN_SCORE)
@Max(MAX_SCORE)
private Integer mathScore;
@NotNull
@Min(MIN_SCORE)
@Max(MAX_SCORE)
private Integer englishScore;
@NotNull
@Min(MIN_SCORE)
@Max(MAX_SCORE)
private Integer chineseScore;
}
位置参数
位置参数由?
+数字构成。
直接看示例:
List<Student> students = session.createQuery("select s from Student s where s.chineseScore>=?1" +
" and s.mathScore>=?2" +
" and s.englishScore>=?3", Student.class)
.setParameter(1, 50)
.setParameter(2, 60)
.setParameter(3, 70)
.getResultList();
students.forEach(s -> {
System.out.println(s);
});
JPQL 中的?1
表示位置为1的参数,该参数由setParameter(1, ...)
设置参数值。
位置参数同样可以在原生 SQL 中使用:
List<Student> students = session.createNativeQuery("select * from student as s where s.chinese_score>=?1" +
" and s.math_score>=?2" +
" and s.english_score>=?3", Student.class)
.setParameter(1, 50)
.setParameter(2, 60)
.setParameter(3, 70)
.getResultList();
命名参数
命名参数由:
+参数名称构成。
示例:
String searchName = "icexmoon";
var student = session.createQuery("select s from Student s where s.name=:name", Student.class)
.setParameter("name", searchName)
.getSingleResult();
可以调用Query.setParameter
并结合参数名称来设置参数值。
同一个名称的参数可以在 JPQL 中使用多次:
var students = session.createQuery("select s from Student s where s.mathScore>=:minScore" +
" and s.englishScore>=:minScore" +
" and s.chineseScore>=:minScore", Student.class)
.setParameter("minScore", 70)
.getResultList();
当然值只需要设置一次。
命名参数同样可以在 Hibernate 的原生 SQL 上使用:
String searchName = "icexmoon";
var student = session.createNativeQuery("select * from student as s where s.name=:name", Student.class)
.setParameter("name", searchName)
.getSingleResult();
不过 JPA 本身并没有要求原生 SQL 必须支持命名参数,所以 Hibernate 的原生 SQL 支持命名参数并不代表所有的 JPA 实现都支持。
集合参数
无论是位置参数还是命名参数,都可以使用集合作为参数值:
var students = session.createQuery("select s from Student s where s.type in :types", Student.class)
.setParameter("types", List.of(Student.Type.HIGH_SCHOOL_STUDENT, Student.Type.COLLEGE_STUDENT))
.getResultList();
条件查询参数
在条件查询(Criterial Query)中同样可以定义参数:
var cb = sessionFactory.getCriteriaBuilder();
JpaCriteriaQuery<Object> query = cb.createQuery();
JpaRoot<Student> root = query.from(Student.class);
JpaParameterExpression<String> nameParam = cb.parameter(String.class);
JpaParameterExpression<Integer> minScoreParam = cb.parameter(Integer.class);
query = query.select(root)
.where(cb.and(cb.equal(root.get("name"), nameParam),
cb.ge(root.get("chineseScore"), minScoreParam),
cb.ge(root.get("mathScore"), minScoreParam),
cb.ge(root.get("englishScore"), minScoreParam)));
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.createQuery(query)
.setParameter(nameParam, "icexmoon")
.setParameter(minScoreParam, 60)
.getSingleResult();
System.out.println(student);
transaction.commit();
session.close();
这里需要用HibernateCriteriaBuilder.parameter
方法创建JpaParameterExpression
对象作为条件查询中的参数对象,该对象可以用于HibernateCriteriaBuilder.ge
或HibernateCriteriaBuilder.equal
这样的 API 构建条件语句,也可以用于Query.setParamter
方法的参数来设置执行查询时的参数值。
The End,谢谢阅读。
可以从这里获取本文的完整实例代码。
参考资料
- JPA Query Parameters Usage | Baeldung