springboot jpa使用:写一个dao层,定义一个接口

// PersonDao.java

@Repository
public interface PersonDao extends JpaRepository<PersonPO,String>, JpaSpecificationExecutor<PersonPO>{

}

在controller层注入,并调用即可

在dao接口中,可以通过jpa的条件构建规则来写一个方法,也可以自定义sql,通常构建规则只能解决简单的需求,复杂的需求还是需要手动写sql来实现。(称作JPQL语句,注意JPQL不支持insert操作

@Modifying
@Transactional
@Query("update CityStationGoods csg set csg.isOnsale = ?2 where csg.id = ?1",nativeQuery=false)
// @Query("update city_station_goods csg set csg.is_on_sale = ?2 where csg.id = ?1",nativeQuery=true)
int updateOnSaleState(int id, Boolean isOnsale);

注意:@Modifying表示除查询外的操作,即对数据库数据有更改。@Transactional表示事务,如果是变更操作需要开启事务才行(该注解可以写在Service或Repository中),@Query的value指定sql,nativeQuery=true表示使用数据库查询,即数据库中表:city_station_goods,否则为本地查询,即使用映射后的实体类作为查询对象,本地PO实体:CityStationGoods

sql中的参数有两种写法:

  • 使用占位符:?1,依据参数顺序从1到n
  • 使用命名参数::name,相应的方法中的参数需要加上注解:@Param("name") String name

1 新增

调用继承过来的方法方法:save()或者saveAll(),传入一个实体或者实体列表进行保存

2 修改

直接编辑SQL

3 删除

默认的删除方法有:

  • delete(实体),只能传入一个可以对应到数据库的实体,即数据库中存在一样的数据的实体
  • deleteInBatch(实体的迭代器),传入一个实体列表,实体同上,在一个语句中进行删除,使用or拼接id(where id=? or id=?..)
  • deleteAll(),删除所有数据项,不过是一条一条删除,会先查询所有项,再删除
  • deleteAll(实体的迭代器),删除所有传入的实体,一条一条删除,
  • deleteAllInBatch(),删除所有数据,一条语句中拼接id删除,同样会先查询出所有的,再删除
  • deleteById(String id),根据id删除某一条数据项

我的需求是根据某个条件删除符合该条件的所有数据项,如果使用默认方法,需要先查询到所有符合的数据项,然后传给删除方法,但是,查询出所有数据项的所有字段增加了网络传输,降低了效率,实际上只需要查出符合条件的id列表即可定位数据项。然后需要批量删除。这个需求只能自己写sql:

// PersonDao.java

@Repository
public interface PersonDao extends JpaRepository<PersonPO,String>, JpaSpecificationExecutor<PersonPO>{
	@Query(value="select id from tb_person where age>?1 limit 0,?2",nativeQuery=true)
	List<String> findId(int age,int num);
	@Transactional
	@Modifying
	@Query(value="delete from tb_person where id in ?1",nativeQuery=true)
	int deleteInIds(List<String> ids);
}

注意:如果查询出来的数据字段不是全部,则返回值如果写成List<PersonPO>可能会报错,如果删除数据过多,建议分批次删除,即查询的时候限制数量,多次查询多次删除。

4 查询

查询可以使用方法命名规则,也可以使用sql来查询,如果是多条件查询,可以使用:Specification

命名规则:
在这里插入图片描述
在这里插入图片描述
手写SQL多条件查询:

@Query(nativeQuery = true, value = "SELECT COUNT(1) FROM trade_info t LEFT JOIN role_info r ON t.role_id = r.id " +
            "WHERE t.order_pay_state <> 1 AND r.nick_name LIKE :nickName" +
            "AND IF(:platform=0, t.pay_type<>0, t.pay_type=:platform) " +
            "AND IF(:maxTime=0, t.create_time IS NOT NULL, UNIX_TIMESTAMP(t.create_time) <= :maxTime) " +
            "AND IF(:minTime=0, t.create_time IS NOT NULL, UNIX_TIMESTAMP(t.create_time) >= :minTime) ")
    public int findFailCount(@Param("nickName") String nickName,
                             @Param("platform") Integer platform,
                             @Param("maxTime") Long maxTime,
                             @Param("minTime") Long minTime);
                             ```
不过这里要注意几个点
1.如果加了@Param这个注解,那SQL里面一定要用冒号来引入参数,如 :key
2.如果没有加@Param,那需要用问号来引入参数,如 ?1

使用Specification:

// 新建一个Specification对象,用于组装条件
Specification<PersonPO> spec = new Specification<PersonPO>(){
	@override
	public Predicate toPredicate(Root<PersonPO> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
		List<Predicate> pList = new ArrayList<>();
		if(StringUtils.isNotEmpty(name)){
			pList.add(criteriaBuilder.like(root.get("name").as(String.class), "%"+name+"%"));
		}
		if(StringUtils.isNotEmpty(code)){
			pList.add(criteriaBuilder.equal(root.get("name").as(String.class), code));
		}
		Predicate[] p = new Predicate[pList.size()];
		return criteriaBuilder.and(pList.toArray(p));
	}
};
Page<PersonPO> all = personDao.findAll(spec,PageRequest.of(pageNum,pageSize));
int dataList = all.getContent(); // 获取所有数据
int num = all.getTotalElements(); // 获取所有记录数

注意:如果多条件查询中,既有and又有or:criteriaQuery.where(predicateAnd,predicateOR).getRestriction()返回一个组合predicate

分页

分页功能实现需要继承JpaRepository
调用:personDao.findAll(PageRequest.of(pageNum,pageSize))即可

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐