JPA多表联查、复杂查询实践

admin 194 0

SpringBoot常用两大SQL持久化框架:Mybatis以及JPA。

关于两者采用哪一种框架,各有利弊。其实,哪一种框架用久了就会很习惯哪一种框架,也就用得顺手了。


一个很鲜明的对比:JPA面向对象,而Mybatis面向关系

面向对象考虑的是对象的整个生命周期包括在对象的创建、持久化、状态的改变和行为等,对象的持久化只是对象的一种状态,而面向关系型数据库的概念则更关注数据的高效存储和读取;

面向对象更强调对象状态的封装性,对象封装自己的状态(或数据)不允许外部对象随意修改,只暴露一些合法的行为方法供外部对象调用;而关系型数据库则是开放的,可以供用户随意读取和修改关系,并可以和其他表任意的关联(只要sql正确允许的情况下);

面向对象试图为动态的世界建模,他要描述的是世界的过程和规律,进而适应发展和变化,面向对象总是在变化中处理各种各样的变化。而关系型模型为静态世界建模,它通过数据快照记录了世界在某一时候的状态,它是静态的。


近些年出的一些关于Mybatis的框架,诸如Mybatis-Plus,则是通过标准CURD的API的SQL查询自动化来提高MyBatis的效率。然而我认为,JPA相较于MyBatis更具有优势,理由是这几点:


  • JPA面向对象封装,数据处理更为安全,更符合Java编程习惯;

  • JPA分页查询自动封装且支持动态分页传参,非常灵活;

(此文简述如何通过Pageable传参,前端可自定义分页参数、排序参数,支持多项不同规则排序:点我跳转)

  • JPA支持JPQL查询,支持MySQL原生语句查询,非常简单;


不定条件动态查询是JPA最大的优势。通过 JpaSpecificationExecutor,可以非常轻松的编写条件查询。比如,查询某个对象的符合条件的一个或多个属性的条件,就可以通过传入对象本身,通过反射以及编写链式对象来做到查询返回结果。

例如我的某个课程查询,封装后这样调用即可:


public Page<Course> findAll(Course course, Pageable pageable){
    return courseRepository.findAll(SFWhere
            .and(course)
            .like(Objects.nonNull(course.getCourseName()),"courseName","%"+course.getCourseName()+"%")
            .like(Objects.nonNull(course.getClasses()),"classes","%"+course.getClasses()+"%")
            .like(Objects.nonNull(course.getTeachingPlace()),"TeachingPlace","%"+course.getTeachingPlace()+"%")
            .build()
            ,pageable);
}

不定条件查询,可多个条件组合查询实例


接下来说到发杂查询,多表联查。JPA继承于Hibernate,所以也具有一对多、多对一的查询。通过中间表等方式可以做到,但问题较多,也可能是本人学术境界不够,在多表上略感JPA的吃力,毕竟面向关系和面向对象不是完全相同的。这时候采取SQL语句查询,则“轻快好省”。


public interface TaskDao extends JpaRepository<Task, Long> {
  @Query("select * from tb_task t where t.task_name = ?1", nativeQuery = true)
  Task findByTaskName(String taskName);
}

原生SQL语句查询


@Query("select distinct p.job from People p where p.job like '%学院%'")
List<String> getAllStudentDepartment();
@Query("select distinct p.organization from People p where length(p.organization) > 4 ")
List<String> getAllTeacherDepartment();

JPQL查询


public interface TaskDao extends JpaRepository<Task, Long> {
   @Query("select t from #{#entityName} t where t.taskName = ? and t.createTime = ?")
  Task findByTaskName(String taskName, Date createTime);
}

还支持SpEL来查询


可以自己封装一个通用接口:

public interface GenericDao<T> extends JpaRepository<T, ID> { 
  @Query("select t from #{#entityName} t where t.id= ?1")   public T findById(Long id);   
}


可以说,JPA插上SQL语句的翅膀,所向无敌。既方便,又兼具高效率。

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~