jpa 常用查询方法记录
以这张表为例:
-
+
-------------+--------------+------+-----+-------------------+----------------+
-
| Field
| Type
|
Null
| Key
|
Default
| Extra
|
-
+
-------------+--------------+------+-----+-------------------+----------------+
-
| id
|
int(
11)
|
NO
| PRI
|
NULL
| auto_increment
|
-
| role
|
varchar(
45)
|
NO
|
|
NULL
|
|
-
| permissions
|
varchar(
512)
|
NO
|
|
NULL
|
|
-
| create_time
| datetime
|
NO
|
|
CURRENT_TIMESTAMP
|
|
-
| status
|
varchar(
45)
|
NO
|
|
NULL
|
|
-
| role_name
|
varchar(
45)
|
NO
|
|
NULL
|
|
-
+
-------------+--------------+------+-----+-------------------+----------------+
CrudRepository 默认带的查询方法
-
@Repository
-
public
interface
RoleRepository
extends
CrudRepository<
RoleData,
Integer> {
-
}
-
-
-
@Entity
-
@Table(name =
"role", catalog =
"message_push")
-
public
class
RoleData
implements java.
io.
Serializable {
-
-
@Id
-
@GeneratedValue
-
private
Integer id;
-
-
private
String role;
-
-
private
String permissions;
-
-
private
Long create_time;
-
-
private
Integer status;
-
-
// getter setter 构造函数从略
-
-
}
简单的扩展-以字段为关键字进行查询
list<RoleData> findByXXX(xxx) 其中 XXX 对应数据库中的字段,例如:
-
@Repository
-
public
interface
RoleRepository
extends
CrudRepository<
RoleData,
Integer> {
-
-
List<
RoleData>
findByRole(
String role);
-
List<
RoleData>
findByStatus(
String status);
-
}
还可以多字段AND 查询:
-
@Repository
-
public
interface
RoleRepository
extends
CrudRepository<
RoleData,
Integer> {
-
-
List<
RoleData>
findByRoleAndStatus(
String role,
String status);
-
}
在 application.properties 中加入以下配置 spring.jpa.show-sql=true 可以看到SQL语句:
Hibernate: select roledata0_.id as id1_0_, roledata0_.create_time as create_t2_0_, roledata0_.permissions as permissi3_0_, roledata0_.role as role4_0_, roledata0_.status as status5_0_ from message_push.role roledata0_ where roledata0_.role=? and roledata0_.status=?
当然 or 也是可以:
List<RoleData> findByRoleOrStatus(String role, String status);
Hibernate: select roledata0_.id as id1_0_, roledata0_.create_time as create_t2_0_, roledata0_.permissions as permissi3_0_, roledata0_.role as role4_0_, roledata0_.status as status5_0_ from message_push.role roledata0_ where roledata0_.role=? or roledata0_.status=?
使用@Query 进行复杂查询
例如:
-
@Query(value
=
"select * from role where role = ?1", nativeQuery
=
true)
-
List<
RoleData> searchByRole(
String role);
或 sql in 用法
-
@Query(value
=
"select * from role where role in (?1) and status = 'valid'", nativeQuery
=
true)
-
List<
RoleData> searchByRoleList(
List<
String> targetList);
又或 sql like 用法:
-
@Query(value
=
"select * from role where role like %?1%", nativeQuery
=
true)
-
List<
RoleData> searchByRole(
String keyWord);
使用 Specification 进行复杂查询
先来看一下 JpaSpecificationExecutor 接口
以 findAll(Specification<T>) 为例进行说明:
Specification<T> 可以理解为一个查询条件。findAll 以这个条件为基准进行查询,也就是我们在sql 里写的 whre xxx 转为 Specification 来写。
首先要让我们的 repository 继承 JpaSpecificationExecutor
-
@Repository
-
public
interface
RoleRepository
extends
CrudRepository<
RoleData,
Integer>,
JpaSpecificationExecutor<
RoleData> {
接下来,将这个查询 [ select * from role where role like '%a%' ] 转为一个简单的 Specification。
-
final
Specification<
RoleData> spec
= new
Specification<
RoleData> () {
-
@Override
-
public
Predicate toPredicate(
Root<
RoleData> root,
CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
-
Predicate predicate
= criteriaBuilder.like(root.get(
"role"),
"%a%");
-
return predicate;
-
}
-
};
然后直接按如下方式调用即可:
roleRepository.findAll(spec);
Specification 里又衍生出了好几个类,分别介绍一下:
Predicate
因为我们实现 Specification 接口时,只需要实现 Predicate toPredicate() 方法。而 Specification 上文中我们当做搜索条件来理解了,那么也可以简单的把 Predicate 视为搜索条件。
CriteriaBuilder
用于构建搜索条件 Predicater 的。
回想一下SQL搜索条件怎么写
where attribute = xx
where attribute > xx
where attribute < xx
where attribute like %xx%
注意这里有三要素:
一 attribute 搜索指定的数据库字段
二 操作符 大于 小于 等于
三 具体数据
CriteriaBuilder提供了一系列静态方法构建这三要素。
比如
CriteriaBuilder.like(数据库字段, 具体数据)
CriteriaBuilder.equal(数据库字段, 具体数据)
其中 数据库字段 不能直接写字符串,需要下一个工具类 Root 的 get 方法获取。
Root
root.get( String attributeName ) 参数 attributeName 就是数据库里的字段名
现在相信读者可以理解 我们刚才写的 那个完整的 Specification了。
再下来再上一个稍微复杂点的例子:
[ select * from role where role like '%a%' and (id > 11 or id < 8) ]
-
final Specification<RoleData> spec =
new
Specification<RoleData> () {
-
@Override
-
public Predicate
toPredicate
(Root<RoleData> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
-
Predicate
roleLikeaPredicate
= criteriaBuilder.like(root.get(
"role"),
"%a%");
-
Predicate
idLessThan8Predicate
= criteriaBuilder.lessThan(root.get(
"id"),
8);
-
Predicate
idGreaterThan12Predicate
= criteriaBuilder.greaterThan(root.get(
"id"),
11);
-
-
Predicate
idCombindedPredicate
= criteriaBuilder.or(idLessThan8Predicate, idGreaterThan12Predicate);
-
Predicate
predicate
= criteriaBuilder.and(idCombindedPredicate, roleLikeaPredicate);
-
-
return predicate;
-
}
-
};
其实也很简单,就是多了 criteriaBuilder.or criteriaBuilder.and 来把多个 Predicate 合成一个新的 Predicate
最后一个例子:
可以通过root.get(xx).in(List<> list) 也是可以直接返回 Predicate 的
-
-
final
Specification<
RoleData> spec2
= new
Specification<
RoleData> () {
-
@Override
-
public
Predicate toPredicate(
Root<
RoleData> root,
CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
-
List<
String> alist
= new
ArrayList<
String>();
-
alist.add(
"admin");
-
Predicate predicate
= root.get(
"role").in(alist);
-
return predicate;
-
}
-
};
还有很多没讲,后续有时间再补充吧。