<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
@Entity @NoArgsConstructor @Data public class ProductLoadRecord implements Serializable { private static final long serialVersionUID = 7676163793637224150L; @Id private Long id; private Long batchId; private String code; private String name; private String content; private String status; @Column(name = "datatime", columnDefinition = "DATETIME") private Date datatime; }
以上的@Entity、@Table、@Column注解的用法可以查阅网址:
https://www.cnblogs.com/softidea/p/6216722.html
public interface OrderRepository extends JpaRepository<OrderInfo,String> { @Query(value="SELECT * from order_info where lock_user_id=?1 AND status=1",nativeQuery=true) List<OrderInfo> selectMyOrders(String lockUserId); @Modifying @Transactional @Query(value="UPDATE order_info SET lock_user_id = NULL AND status = 0 WHERE order_id = ?1",nativeQuery = true) void unlockOrderByOrderId(String orderId); }
public Map select(Integer pageNum,Integer pageSize,Province province){ Page<Province> provinces = provinceRepository.findAll(Example.of(province), PageRequest.of(pageNum - 1, pageSize)); }
@Data @Entity @NoArgsConstructor public class OrderInfo implements Serializable { private static final long serialVersionUID = 1063821955023696541L; @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY) @JoinColumn(name = "orderId") private List<GoodsInfo> goodsInfos; }
复杂的多条件查询需要实现JpaSpecificationExecutor。
public interface OrderRepository extends JpaRepository<OrderInfo,String>, JpaSpecificationExecutor<OrderInfo> { }
service层
重写specification。下面的代码实现了多条件的两表联查分页查询。
通过条件构造中把各种条件拼接在一起,合并成总条件specification。
public Page<OrderInfo> getOrders(OrderPageQuery orderPageQuery){ Specification<OrderInfo> specification = new Specification<OrderInfo>() { @Override public Predicate toPredicate(Root<OrderInfo> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // 建立子查询 Subquery<GoodsInfo> goodsSubquery = query.subquery(GoodsInfo.class); Root<GoodsInfo> goodsInfoRoot = goodsSubquery.from(GoodsInfo.class); goodsSubquery.select(goodsInfoRoot.get("goodsSku")); List<Predicate> orderInfo = new ArrayList<Predicate>(); List<Predicate> goodsInfo = new ArrayList<Predicate>(); Date createStartDate = orderPageQuery.getCreateStartDate(); Date createEndDate = orderPageQuery.getCreateEndDate(); String custName = orderPageQuery.getCustName(); String goodsName = orderPageQuery.getGoodsName(); String custType = orderPageQuery.getCustType(); Integer status = orderPageQuery.getStatus(); if (createStartDate != null && createEndDate != null) { orderInfo.add(cb.between(root.get("createDt"),createStartDate,createEndDate)); } if(custName != null){ orderInfo.add(cb.like(root.get("custName"),"%"+custName+"%")); } if(goodsName != null){ goodsInfo.add(cb.like(goodsInfoRoot.get("goodsName"),"%"+goodsName+"%")); } if(custType != null){ orderInfo.add(cb.equal(root.get("custType").as(String.class),custType)); } if(status != null){ orderInfo.add(cb.equal(root.get("status").as(Integer.class),status)); } if(goodsInfo.size() > 0){ // 子查询与父查询相关联 goodsInfo.add(cb.equal(goodsInfoRoot.get("orderId"),root.get("orderId"))); // 拼接过滤条件 goodsSubquery.where(goodsInfo.toArray(new Predicate[goodsInfo.size()])); // 和总条件拼接(exists的使用) orderInfo.add(cb.exists(goodsSubquery)); } return query.where(orderInfo.toArray(new Predicate[orderInfo.size()])).getRestriction(); } }; Page<OrderInfo> orders = orderRepository.findAll(specification, PageRequest.of(orderPageQuery.getPage() - 1, orderPageQuery.getPageSize())); return orders; }
可以参考下面的网址,一个复杂的查询例子(包含常用的所有查询方法):
https://www.cnblogs.com/g-smile/p/9177841.html
注意:但是这种实现JpaSpecificationExecutor,重写specification的方法,不能单独对表字段查询,例如:
select id,code from order.......,只能相当于select *这样。
实现方式
EntityManager:EntityManager是JPA中用于增删改查的接口,它的作用相当于一座桥梁,连接内存中的java对象和数据库的数据存储。可以用getCriteriaBuilder()的方式获取CriteriaBuilder对象。
CriteriaBuilder接口:用于构造标准查询、复合条件、表达式、排序等。可以通过createQuery的方式获取CriteriaQuery实例。
CriteriaQuery接口:代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by。
Root接口:代表Criteria查询的根对象,定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似 。
实现代码
//通过注解@PersistenceContext注入的方式来获得EntityManager对象 @PersistenceContext private EntityManager entityManager; public void multiQueryStudent (StudentParam studentParam) { //studentParam:自定义的查询参数体 List<String> schoolList = studentParam.getSchoolList(); //查询条件:学校List String startDate = studentParam.getStartDate(); //查询条件:出生日期-起 String endDate = studentParam.getEndDate(); //查询条件:出生日期-止 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); //StudentScoreSum指定了查询结果返回至自定义对象 CriteriaQuery<StudentScoreSum> query = cb.createQuery(StudentScoreSum.class); Root<StudentEntity> root = query.from(StudentEntity.class); Path<String> schoolPath = root.get("school"); Path<Integer> scorePath = root.get("score"); Path<String> namePath = root.get("name"); Path<String> birthdayPath = root.get("birthday"); //拼接where条件 List<Predicate> predicateList = new ArrayList<Predicate>(); if (schoolList != null && schoolList.size() > 0) { CriteriaBuilder.In<String> in = cb.in(schoolPath); for (String school : schoolList) { in.value(school); } predicateList.add(in); } if (startDate != null && !"".equals(startDate)) { predicateList.add(cb.greaterThan(birthdayPath, startDate)); } if (endDate != null && !"".equals(endDate)) { predicateList.add(cb.lessThan(birthdayPath, endDate)); } Predicate[] predicates = new Predicate[predicateList.size()]; predicates = predicateList.toArray(predicates); //加上where条件 query.where(predicates); //指定查询项,select后面的东西 query.multiselect(schoolPath, cb.count(root).as(Integer.class), cb.sum(scorePath), namePath, cb.max(scorePath)); //按学校分组 query.groupBy(schoolPath); //排序 query.orderBy(cb.desc(cb.max(scorePath))); //筛选第一名成绩大于80分的 query.having(cb.greaterThan(cb.max(scorePath), 80)); TypedQuery<StudentScoreSum> q = entityManager.createQuery(query); List<StudentScoreSum> result = q.getResultList(); for (StudentScoreSum studentScoreSum : result) { //打印查询结果 System.out.println(studentScoreSum.toString()); } }
具体可以参考下面的网址:
https://blog.csdn.net/liuyunyihao/article/details/81255731
注意:这种实现方式不能返回分页Page给前端,会把所有的数据查询出来,效率慢。