前言
有人说 从 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 >: