写点什么

序列化与反序列化系列二:JPA 与 Querydsl

发布于: 4 小时前
序列化与反序列化系列二:JPA与Querydsl

系列文章:

序列化与反序列化之 Protostuff(一)


一 前言

其实 JPA 放在这里有些牵强,不过我们开始这个系列的研究是与 JPA 相关的,起源于数据库查询中自动生成的一段 Dabatase 相关代码。事实上,在简化 orm 代码时,序列化和反序列化也确实是其中的一部分重要工作。那么我们就开始本篇学习。

二 spring-data-jpa

2.1 简介

spring-data-jpa 官网:https://spring.io/projects/spring-data-jpa。根据官网的描述:

Spring Data JPA 是 Spring Data 大家族中的一员,使基于 repositories 的 JPA 实现变得简单。本模块对基于 JPA 的数据访问层做了增强支持。它使得构建使用数据访问技术的 Spring 驱动的应用程序变得更加容易。

实现应用的数据访问层通常都很笨重,最典型的就是传统的 JDBC,为了执行简单的一段查询,我们需要写太多重复的(样板)代码。ORM 框架 Hibernate、Mybatis 等都是为了解决这个问题而出现。Spring Data JPA 致力于显著提升数据访问层的代码编写效率,开发者可以写自己的 repository 接口,包括定制化的查询方法,在此之后,Spring 会提供这些接口的自动实现。

2.2 JPA 与 Hibernate 关系

需要注意的是,JPA 仅仅是一种规范,也就是说 JPA 仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,Hibernate 就是实现了 JPA 接口的 ORM 框架。

JPA 默认使用 Hibernate 作为 ORM 实现,所以,一般使用 Spring Data JPA 即会使用 Hibernate。二者的关系就是:JPA 是一套 ORM 规范,Hibernate 实现了 JPA 规范。

根据 Hibernate 官方给出的概念:Hibernate 是一个开源的对象关系映射(ORM)框架,它对 JDBC 进行了非常轻量级的对象封装,它将 POJO 与数据库表建立映射关系,是一个全自动的 ORM 框架,Hibernate 可以自动生成 SQL 语句,自动执行,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

2.3 JPA 与 Mybatis 对比

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Objects,普通的 Java 对象)映射成数据库中的记录。

由于 JPA 默认使用 Hibernate,所以 JPA 与 Mybatis 对比其实就是 Hibernate 与 Mybatis 的对比,这就是一个比较经典的问题了。简单来说:Hibernate 在 Java 代码层面上,省去了绝大部分 sql 编写,取而代之的是用面向对象的方式操作关系型数据库的数据;MyBatis 则是一个能够灵活编写 sql 语句,并将 sql 的入参和查询结果映射成 POJOs 的一个持久层框架。

2.3.1 Mybatis 优势

在做框架选择时,需要考虑功能、灵活性、扩展性等因素。一些倾向于 Mybatis 的理由是,它提供了便利的 SQL 操作,自由度高,封装性好。Spring Data JPA 对复杂 SQL 的支持不好,没有实体关联的两个表要做 join 要花不少功夫。另外几个考虑点:

1.相对来说,jpa 的学习成本比 mybatis 略高 

2.公司业务需求频繁变更导致表结构复杂,此处使用 mybatis 比 jpa 更灵活 

3.就方言来讲,一般公司选定数据库后再变更微乎其微,所以此处方言的优势可以忽略

2.3.2 Hibernate

反过来,Hibernate 自然也有它的优势。在不需要特别复杂 sql 的场景,Hibernate 提供的 SQL 操作功能已经足够应对,它封装好的特征就大有用途了。尤其是在有些场景(一些传统业务),在交付时可能需要根据客户购买的数据库去做适配,这时优势就很明显了。Mybatis 一般都需要做 sql 级别的调整。

三 JPA 之 Querydsl

前面我们已经知道,JPA 对于复杂的 sql 查询,处理起来还是比较复杂的。显然 Spring 也不会放任这个问题一直存在,QueryDSL 就是用来简化 JPA 操作的。

Querydsl 定义了一种常用的静态类型语法,用于在持久域模型数据之上进行查询。JDO 和 JPA 是 Querydsl 的主要集成技术。JPA 的 Querydsl 是 JPQL 和 Criteria 查询的替代方法,以一个通用的查询框架的形式,专注于通过 Java API 构建类型安全的 SQL 查询。

四 Querydsl 使用

4.1 依赖引入

pom 中依赖引入,本文使用的是 4.2.1 版本:

<dependency>    <groupId>com.querydsl</groupId>    <artifactId>querydsl-jpa</artifactId>    <version>4.2.1</version></dependency><dependency>    <groupId>com.querydsl</groupId>    <artifactId>querydsl-apt</artifactId>    <scope>provided</scope>    <version>4.2.1</version></dependency>
复制代码

4.2 maven 编译插件

<plugin>     <groupId>com.mysema.maven</groupId>     <artifactId>apt-maven-plugin</artifactId>     <version>1.1.3</version>     <executions>      <execution>       <goals>        <goal>process</goal>       </goals>       <configuration>        <outputDirectory>target/generated-sources/java</outputDirectory>        <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>       </configuration>      </execution>     </executions> </plugin> 
复制代码

该插件会查找使用 javax.persistence.Entity 注解的域类型,并为它们生成对应的查询类型。例如我们定义一个名为 User 的实体,通过 Querydsl 可以生成一个名为 QUser 的查询。

4.3 User 实体类

package com.flamingskys.springboot.jpa.entity;
import lombok.Data;
import java.io.Serializable;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;
@Data@Entity@Table(name="t_user")public class User implements Serializable{
private static final long serialVersionUID = 1L; @Id() @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; private String address; private int age; @Override public String toString() { return "User [id=" + id + ", name=" + name + ", address=" + address + ", age=" + age + "]"; }}
复制代码

4.4 生成查询类

上述实体类创建好了之后,运行 mvn clean complie 命令,就会在我们在 4.2 中配置的目录下生成对应的查询类型。然后将生成的类拷贝到项目中,就可以使用了。

import static com.querydsl.core.types.PathMetadataFactory.*; import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; import javax.annotation.Generated; import com.querydsl.core.types.Path; /**  * QUser is a Querydsl query type for User  */ @Generated("com.querydsl.codegen.EntitySerializer") public class QUser extends EntityPathBase<User> {  private static final long serialVersionUID = 1153899872L;  public static final QUser user = new QUser("user");  public final StringPath address = createString("address");  public final NumberPath<Integer> age = createNumber("age", Integer.class);  public final NumberPath<Integer> id = createNumber("id", Integer.class);  public final StringPath name = createString("name");  public QUser(String variable) {   super(User.class, forVariable(variable));  }   public QUser(Path<? extends User> path) {   super(path.getType(), path.getMetadata());  }   public QUser(PathMetadata metadata) {   super(User.class, metadata);  } } 
复制代码

这个类就可以实现对单表 t_user 的增删改查操作。

发布于: 4 小时前阅读数: 6
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
序列化与反序列化系列二:JPA与Querydsl