SpringBoot开发案例之整合Spring-data-jpa进阶篇

  • 2019 年 12 月 9 日
  • 筆記

前言

有人说 从 jdbc->jdbctemplate->hibernation/mybatis 再到 jpa,真当开发人员的学习时间不要钱?我觉得到 h/m 这一级的封装已经有点过了,再往深处走就有病了。

还有人说JPA 很反人类(一个面试官),还举了一个很简单举了例子说:一个数据库如果有 50 个字段,那你写各种条件查询不是要写很多?就是应该用类似 SQL 的方式来查询啊?

其实在我看来,存在即合理,人们总是向着好的方向去发展,学习什么不需要成本,底层语言牛逼倒是去学啊,不还是看不懂,弄不明白。很多知识对于程序员来说,都是一通百通,查询文档就是了,最主要的是能方便以后的开发即可。

对于反人类这一说,只能说 to young to simple,JPA的初衷肯定也不会是让你写一个几十个字段的查询,顶多一到两个而已,非要这么极端?再说JPA也是提供了EntityManager来实现SQL或者HQL语句查询的不是,JPA本质上还是集成了Hibernate的很多优点的。

进阶查询

需求:

学生表(app_student)、班级表(app_class)、当然表结构比较简单,比如这时候我们需要查询学生列表,但是需要同时查询班级表的一些数据,并以JSON或者实体的方式返回给调用者。

本次需求,主要实现JPA的以下几个特性:

  • 封装EntityManager基类
  • 多表查询返回一个List
  • 多表查询返回一个Map
  • 多表查询返回一个实体

Entitymanager的核心概念图:

实现

班级表:

@Entity  @Table(name = "app_class")  public class AppClass {      @Id      @GeneratedValue(strategy = GenerationType.AUTO)      @Column(name = "id", nullable = false)      private Integer id;      private String className;      private String teacherName;      //忽略部分代码  }

学生表:

@Entity  @Table(name = "app_student")  public class AppStudent {      @Id      @GeneratedValue(strategy = GenerationType.AUTO)      @Column(name = "id", nullable = false)      private Integer id;      private Integer classId;      private String name;      private Integer age;      //忽略部分代码  }

封装接口 DynamicQuery:

/**   * 扩展SpringDataJpa, 支持动态jpql/nativesql查询并支持分页查询   * 使用方法:注入ServiceImpl   * 创建者 张志朋   * 创建时间    2018年3月8日   */  public interface DynamicQuery {        public void save(Object entity);        public void update(Object entity);        public <T> void delete(Class<T> entityClass, Object entityid);        public <T> void delete(Class<T> entityClass, Object[] entityids);         /**       * 查询对象列表,返回List       * @param resultClass       * @param nativeSql       * @param params       * @return  List<T>       * @Date    2018年3月15日       * 更新日志       * 2018年3月15日  张志朋  首次创建       *       */      <T> List<T> nativeQueryList(String nativeSql, Object... params);         /**       * 查询对象列表,返回List<Map<key,value>>       * @param nativeSql       * @param params       * @return  List<T>       * @Date    2018年3月15日       * 更新日志       * 2018年3月15日  张志朋  首次创建       *       */      <T> List<T> nativeQueryListMap(String nativeSql,Object... params);         /**       * 查询对象列表,返回List<组合对象>       * @param resultClass       * @param nativeSql       * @param params       * @return  List<T>       * @Date    2018年3月15日       * 更新日志       * 2018年3月15日  张志朋  首次创建       *       */      <T> List<T> nativeQueryListModel(Class<T> resultClass, String nativeSql, Object... params);    }

封装实现 DynamicQueryImpl:

/**   * 动态jpql/nativesql查询的实现类   * 创建者 张志朋   * 创建时间    2018年3月8日   */  @Repository  public class DynamicQueryImpl implements DynamicQuery {        Logger logger = LoggerFactory.getLogger(DynamicQueryImpl.class);        @PersistenceContext      private EntityManager em;        public EntityManager getEntityManager() {          return em;      }        @Override      public void save(Object entity) {          em.persist(entity);      }        @Override      public void update(Object entity) {          em.merge(entity);      }        @Override      public <T> void delete(Class<T> entityClass, Object entityid) {          delete(entityClass, new Object[] { entityid });      }        @Override      public <T> void delete(Class<T> entityClass, Object[] entityids) {          for (Object id : entityids) {              em.remove(em.getReference(entityClass, id));          }      }      private Query createNativeQuery(String sql, Object... params) {          Query q = em.createNativeQuery(sql);          if (params != null && params.length > 0) {              for (int i = 0; i < params.length; i++) {                  q.setParameter(i + 1, params[i]); // 与Hiberante不同,jpa                                                      // query从位置1开始              }          }          return q;      }      @SuppressWarnings("unchecked")      @Override      public <T> List<T> nativeQueryList(String nativeSql, Object... params) {          Query q = createNativeQuery(nativeSql, params);          q.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);          return q.getResultList();      }        @SuppressWarnings("unchecked")      @Override      public <T> List<T> nativeQueryListModel(Class<T> resultClass,              String nativeSql, Object... params) {          Query q = createNativeQuery(nativeSql, params);;          q.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));          return q.getResultList();      }        @SuppressWarnings("unchecked")      @Override      public <T> List<T> nativeQueryListMap(String nativeSql, Object... params) {          Query q = createNativeQuery(nativeSql, params);          q.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);          return q.getResultList();      }    }

业务 IStudentService:

public interface IStudentService {       /**        * 返回List<Object[]>        * @Author  科帮网        * @return  List<Object[]>        * @Date    2018年3月28日        * 更新日志        * 2018年3月28日  科帮网 首次创建        *        */       List<Object[]> listStudent();       /**        * 返回List<Student>        * @Author  科帮网        * @return  List<Student>        * @Date    2018年3月28日        * 更新日志        * 2018年3月28日  科帮网 首次创建        *        */       List<Student> listStudentModel();       /**        * List<Map<Object, Object>>        * @Author  科帮网        * @return  List<Map<Object,Object>>        * @Date    2018年3月28日        * 更新日志        * 2018年3月28日  科帮网 首次创建        *        */       List<Map<Object, Object>> listStudentMap();  }

业务实现 StudentServiceImpl:

@Service  public class StudentServiceImpl implements IStudentService {        @Autowired      private DynamicQuery dynamicQuery;          @Override      public List<Object[]> listStudent() {          String nativeSql = "SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c";          List<Object[]> list = dynamicQuery.nativeQueryList(nativeSql, new Object[]{});          return list;      }        @Override      public List<Student> listStudentModel() {          String nativeSql = "SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c";          List<Student> list = dynamicQuery.nativeQueryListModel(Student.class, nativeSql, new Object[]{});          return list;      }        @Override      public List<Map<Object,Object>> listStudentMap() {          String nativeSql = "SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c";          List<Map<Object,Object>> list = dynamicQuery.nativeQueryListMap(nativeSql, new Object[]{});          return list;      }    }

接口测试:

@Api(tags ="测试接口")  @RestController  @RequestMapping("/test")  public class StudentController {      private final static Logger LOGGER = LoggerFactory.getLogger(StudentController.class);        @Autowired      private IStudentService studentService;        @ApiOperation(value="学生List")      @PostMapping("/list")      public Result list(HttpServletRequest request){          LOGGER.info("学生List");          List<Object[]> list = studentService.listStudent();          return Result.ok(list);      }      @ApiOperation(value="学生Map")      @PostMapping("/listMap")      public Result listMap(HttpServletRequest request){          LOGGER.info("学生Map");          List<Map<Object, Object>> list = studentService.listStudentMap();          return Result.ok(list);      }      @ApiOperation(value="学生Model")      @PostMapping("/listModel")      public Result listModel(HttpServletRequest request){          LOGGER.info("学生Model");          List<Student> list = studentService.listStudentModel();          return Result.ok(list);      }  }

Swagger2测试

返回List< Object[] >:

返回List< Map< Object, Object > >:

返回List< Student >:

源码:https://gitee.com/52itstyle/spring-data-jpa