为了配合Repository
的使用,需要定义实体类(比如博客系统中有博客、评论和用户等对象),即定义数据库表到对象的映射关系。回顾Hello World项目中的代码:
package com.tianmaying;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String name;
private String email;
protected User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
}
@Override
public String toString() {
return String.format(
"User[id=%d, name='%s', email='%s']",
id, name, email);
}
}
User
类添加的@Entity
标注表明User
对象将会成为被JPA管理的实体;id
属性上的@Id
和@GeneratedValue(strategy=GenerationType.AUTO)
标注表明id
是一个自增的主键。
接下来我们简单介绍定义实体类时常见的标注。
JPA可以根据实体定义自动生成创建Schema的DDL,它们将会在应用启动时初始化数据库。
可以通过spring.jpa.generate-ddl
属性来开启或者关闭这个特性,比如如果不希望自动生成DDL,则可以在Spring Boot应用配置中声明:
如果使用Hibernate作为JPA的实现,spring.jpa.hibernate.ddl-auto
给出了一种更加细粒度的配置方式,其中包括以下几种取值:
none
:如果是非内嵌数据库,默认为none
,即做任何DDL操作validate
:验证数据库Schema是否和实体类一致update
:更新数据库Schemacreate
:创建数据库Schemacreate-drop
:如果是内嵌数据库(hsqldb、h2和derby),则会默认设置为这个选项;应用结束后会删除Schema在实际生产环境中,一般不会使用内嵌数据库,因此不用专门配置,即默认为none
即可。数据库DDL通常是通过类似Mybatis Migration和Flyway等数据库版本管理工具来维护的。
@Entity
标注用于实体类,表明该Java 类为实体类,将映射到指定的数据库表。
当实体类与其映射的数据库表名不同名时,需要使用@Table
标注说明。@Table
标注与@Entity
标注一同使用,置于实体类声明语句之前。
@Table
标注的常用属性是name
,用于指明数据库的表名。
@Id
标注应用于实体类的属性或者属性对应的getter
方法,表示该属性映射为数据库表的主键。
@GeneratedValue
与@Id
一同使用,表示主键的生成策略,通过strategy
属性指定。
在javax.persistence.GenerationType
中定义了以下几种可供选择的策略:
IDENTITY
:采用数据库ID
自增长的方式产生主键,Oracle不支持这种方式。AUTO
: JPA自动选择合适的策略,是默认选项。SEQUENCE
:通过序列产生主键,通过@SequenceGenerator
标注指定序列名,MySQL不支持这种方式。TABLE
:通过表产生主键,框架借由表模拟序列产生主键,使用该策略更易于做数据库移植。@Basic
表示属性到数据库表的字段的映射。一个@Entity
标注的实体类中的属性,如果没有任何标注,默认即为@Basic
,比如User
类中的name
和email
属性。
@Basic
有两个常用属性:
fetch
: 表示实体类对应属性的读取策略,有EAGER
和LAZY
两种取值,分别表示主动抓取和延迟加载,默认值为EAGER
。
optional
:表示该属性是否允许为null
,默认值为true
。
比如user_table
表的name
字段不能为空,可以如下设置:
@Entity
@Table(name = "user_table")
public class User {
// ...
@Basic(optional = false)
private String name;
}
当实体类的属性与其映射的数据库表的列名称不同时,可以使用@Colunm
标注。该标注描述了数据库表中该字段的详细定义,包含以下属性:
name
:表示数据库表中该字段的名称,默认情形属性名称一致。nullable
:表示该字段是否允许为null
,默认为true
。unique
:表示该字段是否是唯一标识,默认为false
。length
:表示该字段的大小,仅对String
类型的字段有效。insertable
:表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中,默认为true
。updateable
:表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true
。对于一经创建就不能更改的字段,该属性非常有用,比如email
属性。columnDefinition
:表示该字段在数据库中的实际类型。通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是依然有些例外:
Date
类型无法确定数据库中字段类型究竟是DATE
、TIME
还是TIMESTAMP
String
的默认映射类型为VARCHAR
,如果希望将String
类型映射到特定数据库的BLOB
或TEXT
字段类型,则需要进行设置@Transient
表示该属性并非一个到数据库表的字段的映射,JPA将忽略该属性。
如果一个属性并非数据库表的字段映射,就务必将其标注为@Transient
,否则JPA默认其注解为@Basic
。
在数据库中,表示时间类型的数据有 DATE,TIME,和 TIMESTAMP 三种精度 ( 即单纯的日期,时间,或者两者兼备 )。 可使用@Temporal
来设置Date
类型的属性映射到对应精度的字段。
@Temporal(TemporalType.DATE)
映射为日期 // date (只有日期)@Temporal(TemporalType.TIME)
映射为日期 // time (是有时间)@Temporal(TemporalType.TIMESTAMP)
映射为日期 // date time (日期+时间)@Lob
标注表示将属性映射成数据库支持的大对象类型,Clob或者Blog。其中:
java.sql.Clob
、Character[]
、char[]
和 String
将被映射为 Clob 类型。java.sql.Blob
、Byte[]
、byte[]
和 实现了Serializable
接口的类型将被映射为 Blob 类型。因为这两种类型的数据一般占用的内存空间比较大,所以通常使用延迟加载的方式,与@Basic
标注同时使用,设置加载方式为FetchType.LAZY
。
一般情况下并不需要太多的设置,其默认行为足以处理大部分场景,这也是约定大于配置的原则。
可置于属性的标注都能置于对应的getter
,一般情况下应该在整个项目中使用其中一种方式,而不能混用。
更多Entity的标注,参考Hibernate文档
登录发表评论 登录 注册
"updateable" 应该为"@Column(updatable=false)"