使用Spring-Data-JPA操作数据库

1,570 阅读3分钟

创建项目

创建Spring项目,pom文件中主要包含如下依赖:

        // jpa - Java持久化API
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        // web开发
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        // mysql连接
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

下面以Customer对象的持久化为例。

创建Curtomer实体类

创建一个Customer实体类,包含三个域和有参、无参构造函数(有参和无参构造函数必须存在,否则项目运行会报错)。由于id会由注解自动生成,构造函数无需包括id域。

@Entity
@Data
@RequiredArgsConstructor
@NoArgsConstructor
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NonNull
    private String name;
    @NonNull
    private int age;
}

注解@Id表示类Customer类的数据在数据库中的主键为被标注的域id,注解@GeneratedValue表示该类的域id会在类被创建时自动创建,免去了手动生成不重复ID的麻烦。

GenerationType有多种选择,包括:

  • AUTO - 由连接到的数据库的偏好决定
  • SEQUENCE
  • TABLE
  • IDENTITY - 数据库ID自增长
  • UUID
  • CUSTOM
  • NONE - 相当于不加@GeneratedValue注解,一般在由自己写的代码生成ID时使用

创建Repository接口

创建一个继承了CrudRepository的接口CustomerRepository。Spring Data JPA会在运行时自动生成实现类。该类会继承用于数据库操作的函数,直接调用类中的方法就能对数据库进行增删改查。

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> { 
}

传递给CrudRepository的类型参数<S, ID>表示数据库存储的是S实例,主键为ID类型。

在Idea的结构页面中可以看到从CrudRepository继承到的方法。

image.png

配置配置文件

在配置文件aplication.properties中配置数据库连接。

spring.jpa.hibernate.ddl-auto=update
# 数据源,指定MySQL端口和保存的数据库,注意该数据库必须存在
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/hat
# 用户名
spring.datasource.username=root
# 密码
spring.datasource.password=  
# 数据库驱动
spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver  
# 是否在操作数据库时记录日志输出
spring.jpa.show-sql: false  

其中spring.jpa.hibernate.ddl-auto属性的意义在这篇文章中讲得很清楚。

编写RESTful服务

在类CustomerController中编写处理Customer类的Web服务。

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired // 自动装配customerRepository类
    private CustomerRepository customerRepository;

    @PostMapping("/") // 处理`/customer`路径的HTTP POST请求
    public String postHandler(@RequestParam String name,
                              @RequestParam int age) {
        customerRepository.save(new Customer(name, age));
        return "saved!";
    }

    @GetMapping(path = "/{id}", produces = "application/json") // 处理`/customer`路径的HTTP GET请求,指定输出对象为json格式
    public Customer getHandler(@PathVariable Long id) {
        // 调用`orElse`方法,当`findById`给出的`Optional`对象中不包含对象时返回null
        return customerRepository.findById(id).orElse(null);
    }

}

这样,每当/customer路径接收到HTTP GET或者POST请求时,程序就会查询或修改数据库。

测试

启动项目,使用Idea自带的HTTP客户端发送请求。

POST请求存储数据:

POST http://localhost:1000/customer/?name=alice&age=30

HTTP/1.1 200 
Content-Length: 6
Connection: keep-alive
Content-Type: text/plain;charset=UTF-8
Date: Sat, 12 Jun 2021 10:10:06 GMT
Keep-Alive: timeout=4
Proxy-Connection: keep-alive

saved!

Response code: 200; Time: 331ms; Content length: 6 bytes

数据被正常存储到数据库中,存储的表结构为idnameage

GET请求查询数据:

GET http://localhost:1000/customer/3

HTTP/1.1 200 
Transfer-Encoding: chunked
Connection: keep-alive
Content-Type: application/json
Date: Sat, 12 Jun 2021 10:10:21 GMT
Keep-Alive: timeout=4
Proxy-Connection: keep-alive

{
  "id": 3,
  "name": "alice",
  "age": 30
}

Response code: 200; Time: 109ms; Content length: 32 bytes

正常返回了请求的json对象。