2023-03-11
原文作者:柒's Blog 原文地址:https://blog.52itstyle.vip/archives/1304/

202303111616205981.png

前言

有人说 从 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的核心概念图:

202303111616213382.png

实现

班级表:

    @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测试

202303111616218513.png

返回List< Object[] >:

202303111616223454.png

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

202303111616232235.png

返回List< Student >:

202303111616242816.png

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

阅读全文