GraphQL实践1——集成JPA与MySQL

主页地址

介绍

官方定义:

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

中文官网:graphql.cn/

集成方案选择

GraphQL经过近几年的发展,SpringBoot官方、第三方都提供了starter

SpringBoot官方提供的starterspring.io/projects/sp…

第三方提供的startergithub.com/graphql-jav…

两者活跃度都还不错,但考虑到SpringBoot官方的依赖库还未GA,而且使用起来与Spring家族耦合过大,最终决定采用第三方的starter

集成过程

数据库配置

此处采用MySQL数据库,数据内容采用MySQL官方样例sakila数据,表结构和数据地址如下
downloads.mysql.com/docs/sakila…

导入后如下

image-20211105170603665

工程配置

引入最新的SpringBoot框架,依赖如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
xml复制代码<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<!-- https://mvnrepository.com/artifact/com.graphql-java-kickstart/graphql-spring-boot-starter -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>12.0.0</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

增加数据库配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
yaml复制代码spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: "****"
url: jdbc:mysql://localhost:3306/sakila?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL55Dialect
properties:
hibernate:
format_sql: true
use_sql_comments: true
server:
port: 8080
graphql:
tools:
schema-location-pattern: graphql/*.graphqls
graphiql:
# 开启可交互页面,用于调试
enabled: true

实体映射

新增实体映射,此处只映射Actor表作为样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码package top.fjy8018.graphsqldemo.entity;

import lombok.Data;

import javax.persistence.*;
import java.sql.Timestamp;
import java.util.Objects;

/**
* 演员表实体映射
*
* @author F嘉阳
* @date 2021/11/5 10:34
*/
@Data
@Entity
@Table(name = "actor", schema = "sakila")
public class ActorEntity {
@Id
@Column(name = "actor_id", nullable = false)
private Integer actorId;

@Column(name = "first_name", nullable = false, length = 45)
private String firstName;

@Column(name = "last_name", nullable = false, length = 45)
private String lastName;

@Column(name = "last_update", nullable = false)
private Timestamp lastUpdate;
}

新增DAO

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码package top.fjy8018.graphsqldemo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import top.fjy8018.graphsqldemo.entity.ActorEntity;

/**
* 演员表DAO
*
* @author F嘉阳
* @date 2021/11/5 10:35
*/
public interface ActorEntityRepository extends JpaRepository<ActorEntity, Integer> {
}

新增查询接口配置

resources/graphql下新增文件actor.graphqls

1
2
3
4
5
6
7
8
9
10
11
typescript复制代码type Query {
actorList: [ActorEntity]
findOneActor(id : ID!): ActorEntity
}

type ActorEntity {
actorId: ID!
firstName: String!
lastName: String!
lastUpdate: String
}

新增查询解析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
java复制代码package top.fjy8018.graphsqldemo.resolver;

import graphql.kickstart.tools.GraphQLQueryResolver;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import top.fjy8018.graphsqldemo.entity.ActorEntity;
import top.fjy8018.graphsqldemo.repository.ActorEntityRepository;

import java.util.Collection;

/**
* 演员表GraphQL查询解析器
*
* @author F嘉阳
* @date 2021/11/5 16:27
*/
@Component
@AllArgsConstructor
public class ActorGraphQLQueryResolver implements GraphQLQueryResolver {

private final ActorEntityRepository actorRepository;

public Collection<ActorEntity> actorList() {
return actorRepository.findAll();
}

public ActorEntity findOneActor(Integer id) {
return actorRepository.findById(id).orElse(null);
}
}

启动验证

启动工程后,浏览器打开http://localhost:8080/graphiql

image-20211105172013228

列表查询

image-20211105172501790

由于采用交互式页面,输入也会有语法提示,比较方便

image-20211105172405147

唯一查询

image-20211105172219520

优缺点分析

优点

  1. 接口定义清晰,配置即接口
  2. 前端按需获取字段,减少数据传输量
  3. 接口整合、演进更加便利

缺点

  1. 减少字段个数对后端实现没有变化,并不能提升数据库性能

样例源码地址

github.com/FJiayang/gr…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%