个人生活随笔记录,随意参考,不足之处,多多指出哈~
1、jpa对于简单的sql处理确实方便,上面都不用写,dao层方法名拼接好就对了,命名规则自行百度。
2、之前做了一个需要分页、多表关联、多条件查询的需求,当时项目集成的是jpa,如果是其他比如mybatis、mybatis-plus这些那太好实现了,过于复杂如果plus不好拼,大不了直接xml写sql就行。
3、jpa的dao层一般是这样写的
public interface XXXRepository extends JpaRepository<XXXEntity, ID类型>, JpaSpecificationExecutor<XXXEntity> {
}
之所以继承JpaSpecificationExecutor这个接口类,是因为觉得方便,直接可以在service调用以下分页接口
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
也可以不继承,自己手动在XXXRepository 里面定义一个相同接口就行
4、分页需要用到Pageable类,多条件的时候要用到Specification类,说实话如果不用这个,在dao层定义的接口上也可以实现,但是sql量太大了,拼起来麻烦,而且改动的时候不方便,比如单个查询的时候
//nativeQuery = true 意思是执行原生sql,都是直接对应数据库字段名的
@Query(value = "select * from tableName where code like concat('%',?1,'%')",nativeQuery = true)
List<Entity> findByCode(String code);
多条件查询的时候
@Query(value = "select * from tableName where if(?1 !='',code like concat('%',?1,'%'),1=1)",nativeQuery = true)
List<Entity> findByCode(String code);
单纯举个例,上面这些写法也行,但是sql量太大的时候,用Specification类来拼装SQL比较明智
5、分页+多条件查询写法
//page是当前页码,size是当前页最大显示数量
//由于查询page是从0开始的,所以如果前端传过来页码是1,那么这里记得page-1
Pageable pageable = PageRequest.of(page,size);
//拼接sql
Specification<XXXEntity> specification = (root, query, criteriaBuilder)->{
...
}
//执行sql
Page<XXXEntity> page = repository.findAll(specification,pageable);
//page内返回内容,挑几个比较关键的
//当前页码,返回的值需要+1(这里看个人业务场景,正常情况前端页面的页面都是从1开始,所以这里+1,也可以前端处理)
page.getPageable().getPageNumber();
//每一页最大返回数量
page.getPageable().getPageSize();
//返回分页数量,就是总的数据可以分出来多少页
page.getTotalPages();
//返回所有数据的总量
page.getTotalElements();
Specification内部拼装sql的写法
假设场景:用户表关联角色表,关系存在他们的关联表里面,每一条关联都存上了user_id、role_id
假设类:用户 User.class,角色Role.class,用户角色关联 UserRole.class
(root, query, criteriaBuilder)->{
//Join这里先写,在下面说明一下这种写法
Join<User,UserRole> userRole = root.join("userRole",JoinType.LEFT);
Join<User,Role> role = userRole.join("role",JoinType.LEFT);
if(条件判断){
//查询用户性别
//这里是拼接的精确匹配 and xxx=?
list.add(criteriaBuilder.equal(root.get("userSex"),"条件值"));
}
if(条件判断){
//查询拥有某个角色名的用户,模糊匹配
//这里是拼接的模糊匹配 and xxx like ‘%’ ? ‘%’
list.add(criteriaBuilder.like(role.get("name"),"%"+输入内容+"%"));
}
if(条件判断){
//查询关键字段,比如搜索框输入内容可以匹配用户名、角色名,任意匹配一个就返回这种
list.add(criteriaBuilder.or(
criteriaBuilder.like(root.get("userName"),"%"+输入内容+"%"),
criteriaBuilder.like(root.get("roleName"),"%"+输入内容+"%")));
}
//数据去重 ,这里如果用query.groupBy有可能导致返会page里面总数为数据表内的总数
//具体详情大家可以去百度了解一下,是因为会首先查询一次不带条件时的sql统计出来的
query.distinct(true);
//数据排序,比如这里根据创建日期排
Order order = criteriaBuilder.desc(root.get("createdTime"));
query.orderBy(order);
//这里完成最终的拼接,这里也可以自己根据实际条件判断一下,比如list可能无值的情况下
Predicate[] p = new Predicate[list.size()];
return criteriaBuilder.and(list.toArray(p));
}
6、Join关联查询这里,如何拼接成 select * from user_table u left join role_table r on r.user_id = u.id
就可以按照这个写法
Join<User,UserRole> userRole = root.join("userRole",JoinType.LEFT);
Join<User,Role> role = userRole.join("role",JoinType.LEFT);
上面代码在模糊匹配角色名的时候,注意用的是 role.get("")而不是root.get(),
因为root代表的是主表,而role是在左连接之后的Role表
root.join里面的userRole、role,这里的命名是按照下面的实体类取的值
User.class,Role.class,UserRole.class
//User实体映射类里面,比如和角色是一对多的关系按照以下的写法就行,上面的userRole也就是取的这里的userRole。
@OneToMany(targetEntity = UserRole.class)
@JoinColumn(name = "user_id",referencedColumnName = "id")
private Set<UserRole> userRole;
name=“user_id” 代表的是 UserRole.class里面的字段user_id,
referencedColumnName =‘id’ 是当前User类的字段。这个写法就表示 r.user_id = u.id 关联关系
jpa多表+多条件+分页查询 写法大概就这样,具体写法需要根据具体的业务场景扩展或者根据个人需要改动就行