spring data 常用的几种CURD方法
1. 通过解析方法名创建查询
框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。
在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByUserAddressZip ()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假设该方法针对的域对象为 AccountInfo 类型):
- 先判断 userAddressZip (根据 POJO 规范,首字母变为小写,下同)是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;
- 从右往左截取第一个大写字母开头的字符串(此处为 Zip),然后检查剩下的字符串是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user 为 AccountInfo 的一个属性;
- 接着处理剩下部分( AddressZip ),先判断 user 所对应的类型是否有 addressZip 属性,如果有,则表示该方法最终是根据 “AccountInfo.user.addressZip” 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 “AccountInfo.user.address.zip” 的值进行查询。
在查询时,通常需要同时根据多个属性进行查询,且查询的条件也格式各样(大于某个值、在某个范围等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:
- And — 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
- Or — 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
- Between — 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
- LessThan — 等价于 SQL 中的 “<”,比如 findBySalaryLessThan(int max);
- GreaterThan — 等价于 SQL 中的”>”,比如 findBySalaryGreaterThan(int min);
- IsNull — 等价于 SQL 中的 “is null”,比如 findByUsernameIsNull();
- IsNotNull — 等价于 SQL 中的 “is not null”,比如 findByUsernameIsNotNull();
- NotNull — 与 IsNotNull 等价;
- Like — 等价于 SQL 中的 “like”,比如 findByUsernameLike(String user);
- NotLike — 等价于 SQL 中的 “not like”,比如 findByUsernameNotLike(String user);
- OrderBy — 等价于 SQL 中的 “order by”,比如 findByUsernameOrderBySalaryAsc(String user);
- Not — 等价于 SQL 中的 “! =”,比如 findByUsernameNot(String user);
- In — 等价于 SQL 中的 “in”,比如 findByUsernameIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
- NotIn — 等价于 SQL 中的 “not in”,比如 findByUsernameNotIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
2. 使用 @Query 创建查询
几个简单的例子进行展示
// 原生sql
@Query(value = "select * from book b where b.name=?1", nativeQuery = true)
List<Book> findByName(String name);
// 对应的实体
@Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
List<Book> findByPriceRange(long price1, long price2);
@Query(value = "select name,author,price from Book b where b.name like %:name%")
List<Book> findByNameMatch(@Param("name") String name);
// 更新操作加@Modifying
@Modifying
@Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2")
public int increaseSalary(int after, int before);
// 返回值为Object[]
@Query(value = "SELECT COUNT(CASE WHEN TO_DAYS(foll_time) = TO_DAYS(NOW()) THEN foll_time END) AS dayFollowCount," +
"COUNT(CASE WHEN DATE_FORMAT(foll_time,'%Y%m') = DATE_FORMAT(CURDATE(),'%Y%m') THEN foll_time END) AS monthFollowCount " +
"FROM acc_followup WHERE creator = :userName",nativeQuery = true)
Object[] getOperatorDate(@Param("userName") String userName);
3. 使用EntityManager创建查询
public class StudentRepositoryImpl {
@PersistenceContext
private EntityManager em;
@SuppressWarnings("unchecked")
public Page<Student> search(User user) {
String dataSql = "select t from User t where 1 = 1";
String countSql = "select count(t) from User t where 1 = 1";
if(null != user && !StringUtils.isEmpty(user.getName())) {
dataSql += " and t.name = ?1";
countSql += " and t.name = ?1";
}
Query dataQuery = em.createQuery(dataSql);
Query countQuery = em.createQuery(countSql);
if(null != user && !StringUtils.isEmpty(user.getName())) {
dataQuery.setParameter(1, user.getName());
countQuery.setParameter(1, user.getName());
}long totalSize = (long) countQuery.getSingleResult();
Page<User> page = new Page();
page.setTotalSize(totalSize);
List<User> data = dataQuery.getResultList();
page.setData(data);
return page;
}
}
4. 使用spring data jpa动态扩展查询(JpaSpecificationExecutor)
@RequestMapping(value = "/getAccCustomerQueryList", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ApiOperation(value = "客户查询", notes = "客户查询(分页、条件)")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", dataType = "integer", paramType = "query", value = "页数 (0..N)"),
@ApiImplicitParam(name = "size", dataType = "integer", paramType = "query", value = "每页大小."),
@ApiImplicitParam(name = "sort", dataType = "string", paramType = "query", value = "依据什么排序: 属性名(,asc|desc). ", allowMultiple = true)
})
public Result getAccCustomerQueryList(@RequestParam(required = false) @ApiParam("批次号") String cupoBatch,
@RequestParam(required = false) @ApiParam("委托方ID") String prinId,
@RequestParam(required = false) @ApiParam("申请省份") String province,
@RequestParam(required = false) @ApiParam("申请城市") String city,
@RequestParam(required = false) @ApiParam("客户名称") String custName,
@RequestParam(required = false) @ApiParam("手机号码") String cupoPhone,
@ApiIgnore Pageable pageable) {
logger.debug("REST request to get CustomerQueryList by page");
try {
Specification<AccRecevicePool> specification = (root, criteriaQuery, criteriaBuilder) -> {
Predicate predicate = criteriaBuilder.conjunction();
if (StringUtils.isNoneBlank(cupoBatch)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("cupoBatch"), cupoBatch));
}
if (StringUtils.isNoneBlank(prinId)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("prinId"), prinId));
}
if (StringUtils.isNoneBlank(custName)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("custName"), custName.trim()));
}
if (StringUtils.isNoneBlank(province)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("cupoPrid"), province));
}
if (StringUtils.isNoneBlank(city)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("cupoCityid"), city));
}
if (StringUtils.isNoneBlank(cupoPhone)) {
predicate.getExpressions().add(criteriaBuilder.equal(root.get("cupoPhone"), cupoPhone));
}
//把流转流出的数据干掉
predicate.getExpressions().add(criteriaBuilder.notEqual(root.get("cupoStatus"), 71));
return predicate;
};
Page<AccRecevicePool> page = accCustomerQueryService.findAll(Specifications.where(specification), pageable);
return new Result(Result.ReturnValue.SUCCESS, "", page);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new Result(Result.ReturnValue.FAILURE, Constants.ERROR_MESSAGE);
}
}
5. 对mongodb的支持
CustomerRepairInformation customerRepairInformation = new CustomerRepairInformation();
customerRepairInformation.setCustomerInformationId(customerId);
ExampleMatcher matcher = ExampleMatcher.matching();
Example<CustomerRepairInformation> example = Example.of(customerRepairInformation, matcher);
Page<CustomerRepairInformation> page = customerRepairInformationService.findAll(example, pageable);
return new Result(Result.ReturnValue.SUCCESS, "", page);
Query query = new Query();
query.addCriteria(Criteria.where("userId").is(userId));
// 客户名称模糊查询
if (StringUtils.isNotBlank(custName)) {
query.addCriteria(Criteria.where("custName").regex(custName));
}
if (StringUtils.isNotBlank(IdCardNumber)) {
query.addCriteria(Criteria.where("idCardNumber").is(IdCardNumber));
}
if (StringUtils.isNotBlank(phoneNum)) {
query.addCriteria(Criteria.where("phoneNum").is(phoneNum));
}
// 省份左匹配
if (StringUtils.isNotBlank(province)) {
Pattern pattern = Pattern.compile("^" + province + ".*$", Pattern.CASE_INSENSITIVE);
query.addCriteria(Criteria.where("province").regex(pattern));
}
// 城市左匹配
if (StringUtils.isNotBlank(city)) {
Pattern pattern = Pattern.compile("^" + city + ".*$", Pattern.CASE_INSENSITIVE);
query.addCriteria(Criteria.where("city").regex(pattern));
}
int total = (int) mongoTemplate.count(query, AreaReviseData.class);
query.with(pageable);
List<AreaReviseData> list = mongoTemplate.find(query, AreaReviseData.class);
return new Result(Result.ReturnValue.SUCCESS, "", new PageImpl<>(list, pageable, total));
持续更新中。。。