­

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