# Spring Data JPA 使用方法

***

JPA是Java官方定义的一套与数据库交互的接口标准。Spring Data JPA 实现了它，并且整合了多种数据库，使得与数据库的交互变得简单。

使用Spring Data JPA的逻辑：

> 在springApplication设置里设置数据源（datasource）；
>
> 编写一个实体类，其中的属性对应数据库表单的列；
>
> 为这个实体类添加注解，使其能够与数据表衔接；
>
> 定义Dao（Repository），使用它来与数据库进行交互。

## 一、导入包

首先用maven导入包：

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
 </dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
```

这里导入lombok，用于生成构造方法；导入mysql-connector，用于连接mysql数据库，与mysql交互这个是必须的。

## 二、创建数据库

在外部（cmd）登录mysql并使用SQL语句创建数据库`jpatest`，新建一个表`users`用来储存用户数据。

```sql
mysql> create table users (
    -> id int,
    -> name char(30),
    -> password char(30),
    -> userInfoId int);
```

然后用ALTER指令设置id为主键，并设置其为自增。

创建完成后可以用IDEA自带的database工具登录数据库并查看：

![IDEA的database工具](https://s1.328888.xyz/2022/09/17/o9Gan.png)

> 这里注意，IDEA的database窗口只是用于预览数据库和数据表，并不能让项目连上数据库。还需要手动设置datasource。

## 三、配置数据源

在Spring设置（`application.properties`，一般在`resources`目录下，也有一种写为yml形式）中添加如下语句以添加数据源：

```properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpatest?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=password
```

这样就指定了一个数据源，其驱动为mysql驱动，数据库的url为`mysql://localhost:3306/jpatest`，也就是`jpatest`数据库。然后我们指定了用户名和密码。

## 四、创建实体类

对应我们的需求和数据库的各列，我们新建下面的User类：

```java
import lombok.*;
import javax.persistence.*;

@Data
@RequiredArgsConstructor
@NoArgsConstructor
@Entity
@Table(name="users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @NonNull
    private String name;
    @NonNull
    private String password;
    @NonNull
    @Column(name="userinfoid")
    private int userInfoId;
}
```

下面对类上的注解进行说明。这些注解都是由`javax.persistence`定义的。

### @Data、@RequiredArgsConstructor 和@NoArgsConstructor

都是lambok提供的。`@Data`提供getter和setter，`@NoArgsConstructor`提供`@Entity`要求的无参构造方法，而`@RequiredArgsConstructor`则提供仅包含必须的几个属性（这里是除了id以外的属性，因为id我们希望它自动生成）的构造方法。

`@RequiredArgsConstructor` 只会识别带有lombok的`@NonNull`注解或`final`修饰符的属性。所以在相关属性上加上`@NonNull`。

> p.s. 好像很多人用`@RequiredArgsConstructor`不需要使用@NonNull，但我本地没办法不用@NonNull实现。

### @Entity、@Id 和 @Table

`@Entity`注解会将这个类表示为准备映射数据库的实体类，必须结合@Id注解使用。

`@Id`所标注的属性会被识别为主键。一个表必须有主键，所以必须存在这个注解。

> `@GeneratedValue`用于给主键指定生成策略，一般用`GenerationType.IDENTITY`来指定主键为自增。这里的注解设置必须和数据库一致，否则会出错。

`@Table`用于标识需要对应的数据表名。如`@Table(name="users")`表示对应的是数据源下的`users`这个表。

### @Column

这个注解用于属性上，可写可不写，用于指定这个属性所对应的列的名字。如果不写，那么指定的列默认是和这个属性名字相同的列。注意大小写是敏感的，要和数据库严格一致。

## 五、创建UserRespository

这就是所谓的Dao层，由Spring提供具体实现。我们在这里需要定义一个接口`UserRespository`，继承Spring提供的接口`JpaRepository< >`以使用Spring提供的方法。

```java
@Repository
public interface UserRepository extends JpaRepository<User,Integer> {

}
```

### 说明：

* `JpaRepository< >`需要提供实体类和ID（主键）的类；
* 为了之后让Spring托管这个类，加上`@Repository`注解使之被定义为一个bean；
* 只要留空这个接口就可以使用了。

在留空这个接口的情况下，就可以执行`save`，`saveall`，`delete`，`find`等等的CRUD（增删查改）操作了。但是由于`JpaRepository`实现的时候不知道你的类有哪些属性，所以要进行一些具体的操作，比如`findByPassword`（根据密码查找用户），就必须要在这个接口下自定义一些方法来完成。

Spring Data的一个强大的功能在于，你只需要在接口定义这个方法，而不需要实际写代码来实现它，Spring框架会自动理解你的方法的目的，并自动帮你实现想要的操作。

例如，上面提到的`findByPassword`可以直接用这样的方式实现：

UserRepository：

```java
@Repository
public interface UserRepository extends JpaRepository<User,Integer> {
    public User getByPassword(String passwd);
}
```

test()：

```java
user = userRepository.getByPassword("123");
```

虽然我们没有编写任何实现相关代码，但Spring仍通过解析方法名的意义帮你完成了你想要的操作。

除了匹配具体的数值，方法名的解析还支持值区间、包含、前缀等等非常丰富的匹配方法。这些方法在书写时IDEA都会提供补全的提示，非常方便。

当然，有时候我们还是会想用sql的方式进行操作，也可以使用`@Query`注解实现。

例子：

```java
    @Query(value = "select u from User u where u.password='123'")
    public User getByPassword2();
```

这个语法和原生的sql有所不同，需要单独查阅。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.mcyou.cc/hou-duan-xiang-guan/springdatajpa-shi-yong-fang-fa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
