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