> For the complete documentation index, see [llms.txt](https://spring-boot.shujuwajue.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://spring-boot.shujuwajue.com/guan-xi-xing-shu-ju-ku/spring-data-jpa/bei-zhu.md).

# 配置与注解备注

## 配置备注

### `spring.jpa.generate-ddl` 与 `spring.jpa.hibernate.ddl-auto`

spring.jpa.hibernate.ddl-auto 其实对应的是hibernate里的`hibernate.hbm2ddl.auto.`

默认情况下，DDL执行（或验证）被延迟到ApplicationContext启动。这也有一个spring.jpa.generate-ddl标识，如果Hibernate自动配置被激活，那该标识就不会被使用，因为ddl-auto设置粒度更细，推荐。

`spring.jpa.hibernate.ddl-auto 支持的值：`

* ddl-auto:create----每次运行该程序，没有表格会新建表格，表内有数据会清空
* ddl-auto:create-drop----每次程序结束的时候会清空表
* ddl-auto:update----每次运行程序，没有表格会新建表格，表内有数据不会清空，只会更新
* ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同，不同会报错

`spring.jpa.generate-ddl支持 值:`

* true
* false

## 注解备注

### `@EntityGraph注解`

[JPA效率优化（EntityGraph）](https://blog.csdn.net/dalangzhonghangxing/article/details/56680629)

例子： 表示根据name查询书的时候也把关联 category的信息和作者信息都查出来

```java
public interface BookRepository extends BookShopRepository<Book> {

    @EntityGraph(attributePaths = { "category","authors"  })
    Book findByName(String bookname);

}
```

可以统一写在对象实体类上面，并且以一个自定义的name命名，这样中就可以使用名字来统一引用

entity实体类中：

```java
@Entity
@NamedEntityGraph(name = "Book.fetch.category.and.author", attributeNodes = {
 @NamedAttributeNode("category"),
 @NamedAttributeNode("authors")
})
public class Book extends DomainImpl {
  ....省略
}
```

BookRepository 类中就可以使用名字进行引用

```java
public interface BookRepository extends BookShopRepository<Book> {

    @EntityGraph("Book.fetch.category.and.author")
    Book findByName(String bookname);

}
```

这样做的好处是如果抓取策略变了，只需要改源头，因为引用处都是使用name

### `@Inheritance注解`

实体继承策略的注解

JPA提供了三种继承映射策略：

* 1、 一个类继承结构一个表的策略。这是继承映射的默认策略。即如果实体类B继承实体类A，实体类C也继承自实体A，那么只会映射成一个表，这个表中包括了实体类A、B、C中所有的字段，JPA使用一个叫做“discriminator列”来区分某一行数据是应该映射成哪个实体。注解为：`@Inheritance(strategy = InheritanceType.SINGLE_TABLE)`
* 2、 联合子类策略。这种情况下子类的字段被映射到各自的表中，这些字段包括父类中的字段，并执行一个join操作来实例化子类。注解为：`@Inheritance(strategy = InheritanceType.JOINED)`
* 3、 每个具体的类一个表的策略。注解为：`@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)`

```java
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Book {
}
```

> 注意：如果使用`TABLE_PER_CLASS`这种策略主键是不能使用自增主键策略，因为`TABLE_PER_CLASS`会每个具体类创建一个表，每个表都有自己的主键，如果使用自增策略，这两个表里的主键有可能会重复，导致语句查询时候产生混乱。则需要自己写主键id的生成策略
>
> ```java
> @Id
> @GeneratedValue(generator = "sequenceGenerator")
> @GenericGenerator(name = "sequenceGenerator", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
>     parameters = {
>         @Parameter(name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "ID_SEQUENCE"),
>         @Parameter(name = SequenceStyleGenerator.INITIAL_PARAM, value = "1000"),
>         @Parameter(name = SequenceStyleGenerator.INCREMENT_PARAM, value = "1"),
>         @Parameter(name = SequenceStyleGenerator.OPT_PARAM, value = "pooled"),
>     }
> )
> private Long id;
> ```

[JPA实体继承实体的映射策略](https://blog.csdn.net/mhmyqn/article/details/37996673)

[hibernate 在mysql数据库上，利用sequence生成主键的另一种解决方法](http://bastengao.iteye.com/blog/1105650)

### `@Basic注解`

JPA不会去修改已经生成出来的表名或者字段名，新增的字段，如果没有添加任何注释标签，则自动会有一个`@Basic`注解，作用就是自动会在数据库中添加此字段。

### `@Table注解`

当你的entity名和你表名不一致时，`@Table(name="CUSTOMERS") ，@Tablel来明确指定一个表名。`

### `@Column注解`

当你的entity属性名和数据库中的字段名不一致，可以使用`@Column` 明确指定，它也可以设置一些属性

```java
@Column(length = 10, nullable = false, unique = true)
```

```java
@Column(columnDefinition = "INT(3)")
private int age;
```

支持的参数，参考：[@Column 注解详情](https://www.cnblogs.com/ConfidentLiu/p/7710493.html) , [JPA的Column注解总结](https://www.cnblogs.com/quickcodes/p/JPA-deColumn-zhu-jie-zong-jie.html)

* unique属性表示该字段是否为唯一标识，默认为false。如果表中有一个字段需要唯一标识，则既可以使用该标记，也可以使用@Table标记中的@UniqueConstraint。
* nullable属性表示该字段是否可以为null值，默认为true。
* insertable属性表示在使用“INSERT”脚本插入数据时，是否需要插入该字段的值。
* updatable属性表示在使用“UPDATE”脚本插入数据时，是否需要更新该字段的值。insertable和updatable属性一般多用于只读的属性，例如主键和外键等。这些字段的值通常是自动生成的。
* columnDefinition属性表示创建表时，该字段创建的SQL语句，一般用于通过Entity生成表定义时使用。
* table属性表示当映射多个表时，指定表的表中的字段。默认值为主表的表名。有关多个表的映射将在本章的5.6小节中详细讲述。
* length属性表示字段的长度，当字段的类型为varchar时，该属性才有效，默认为255个字符。
* precision属性和scale属性表示精度，当字段类型为double时，precision表示数值的总长度，scale表示小数点所占的位数。

### `@Transient注解`

@Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.

如果一个属性并非数据库表的字段映射,就务必将其标示为`@Transient`,否则,ORM框架默认其注解为`@Basic`

示例:

```java
//根据birth计算出age属性 
@Transient 
public int getAge() { 
    return getYear(new Date()) - getYear(birth); 
}
```

### @Enumerated`注解`

```
@Enumerated(EnumType.STRING)
private Gender gender;
```

Gender.java

```java
public enum Gender {
    male("男"),
    female("女");

    private String name;
    }

    public String getName(){
        return this.name;
    }
}
```

这样存入数据库中时是枚举字符串，而非0 ，1 的数字

[JPA关于枚举类型的处理](https://www.jianshu.com/p/71185c21f5b5)

[JPA 中@Enumerated](https://blog.csdn.net/qq_38157516/article/details/80540505)

[JPA之日期和枚举的JPA映射](https://blog.csdn.net/BruceLeeNumberOne/article/details/77828603)

### @Temporal`注解`

```
@Temporal(TemporalType.DATE)
private Date birthday;
```

为日期格式：2018-06-18

```java
@Temporal(TemporalType.TIME)
```

为时间格式：22:50:30

```java
@Temporal(TemporalType.TIMESTAMP)
```

日期和时间(默认)格式:2011-06-18 22:51:34.0

[Hibernate JPA注解 @Temporal(TemporalType.DATE) 日期注解!](https://blog.csdn.net/u013456370/article/details/52691093)

### `@Valid`

字段验证

[使用validator-api来验证spring-boot的参数](https://www.cnblogs.com/mawang/p/6767906.html)

### @MappedSuperclass

当有entity里有共同的属性字段，比如说id，则可以把他提炼出来一个父类，并且加上`@MappedSuperclass`，则实体基类就可以继承了

### `@NoRepositoryBean`

启动时不初始化该实体类。是spring date jpa的一种注解

[Spring Data JPA: 为所有Repository添加自定义方法](https://www.tianmaying.com/tutorial/spring-jpa-custom-all)
