Java Persistence API
1. 基本注解
1.1 @Entity
由 @Entity
定义的对象会成为被 JPA 管理的实体,将映射到指定的数据库表中。
public @interface Entity {
//可选,默认是此实体类名,全局唯一
String name() default "";
}
1.2 @Table
用于指定数据库的表名。
public @interface Table {
//表的名字,如果不写,则默认与实体的名字一样
String name() default "";
//此表的catalog
String catalog() default "";
//此表的schema
String schema() default "";
//唯一性约束,只有创建表的时候用,默认不需要
UniqueConstraint[] uniqueConstraints() default {};
//索引,只有创建表的时候使用,默认不需要
Index[] indexes() default {};
}
1.3 @Id
定义数据库的主键,一个实体里至少有一个主键。
1.4 @IdClass
联合主键。
public @interface IdClass {
//联合主键的类
Class value();
}
联合主键的用处就是一个表中能存在多个主键,这些主键在关联在外部的一个对象中,这个对象需要满足以下条件
- 必须实现
Serializable
接口 - 必须有默认的
public
无参构造方法 - 必须覆盖
equals()
和hashCode()
方法
1.5 @GeneratedValue
主键生成策略。
public @interface GeneratedValue {
//Id生成策略,默认GenerationType.AUTO
GenerationType strategy() default GenerationType.AUTO;
//通过Sequences生成Id,常见的是Orcale数据库的Id生成规则,需要配合@SequenceGenerator使用
String generator() default "";
}
public enum GenerationType {
//通过表产生主键,框架由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植
TABLE,
//通过序列产生主键,通过@SequenceGenerator注解指定序列名,Mysql不支持这种方式
SEQUENCE,
//采用数据库Id自增,用于Mysql数据库
IDENTITY,
//JPA默认选项,自动选择策略
AUTO;
private GenerationType() {
}
}
1.6 @Basic
@Basic
表示属性是到数据库的字段的映射,如果实体的字段上没有任何注解,默认为 @Basic
。
public @interface Basic {
//EAGER是立即加载,这是默认方式,可以看到还有一种LAZY懒加载
FetchType fetch() default FetchType.EAGER;
//Optional 类是一个可以为null的容器对象,设置为true,则表示字段可以为null,默认可以
boolean optional() default true;
}
public enum FetchType {
LAZY,
EAGER;
private FetchType() {
}
}
1.7 @Transient
@Transient
表示该属性并非一个到数据库表的字段的映射,是非持久化属性,与 @Basic
作用相反。
实体中有数据库中不存在的字段,可以加上 @Transient
注解,忽略这个字段的映射。
1.8 @Column
public @interface Column {
String name() default "";
//表示该字段是否为唯一标识,默认为false,如果表中有一个字段需要唯一标识,则既可以使用该标记,也可以使用@Table标记中的@UniqueConstraint
boolean unique() default false;
//数据字段是否允许为空,默认允许
boolean nullable() default true;
//执行insert操作时是否包含此字段,默认包含
boolean insertable() default true;
//执行update操作时是否包含此字段,默认包含
//insertable和updatable属性一般多用于只读的属性,例如主键和外键等。这些字段的值通常是自动生成的
boolean updatable() default true;
//表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用
String columnDefinition() default "";
//表示当映射多个表时,指定表的表中的字段。默认值为主表的表名
String table() default "";
//字段长度,默认255
int length() default 255;
// precision 属性和 scale 属性表示精度,当字段类型为double时,precision表示数值的总长度,scale表示小数点所占的位数
int precision() default 0;
int scale() default 0;
}
1.9 @Temporal
@Temporal
用来设置 Date 类型的属性映射到对应精度的字段,也就是对日期进行格式化。
public enum TemporalType {
DATE,
TIME,
TIMESTAMP;
private TemporalType() {
}
}
public @interface Temporal {
TemporalType value();
}
public enum TemporalType {
DATE,
TIME,
TIMESTAMP;
private TemporalType() {
}
}
可以看到有三种格式化方式,
-
@Temporal(TemporalType.DATE)
: 实体类会封装成日期yyyy-MM-dd
的 Date 类型。 -
@Temporal(TemporalType.TIME)
: 实体类会封装成时间hh-MM-ss
的 Date 类型。 -
@Temporal(TemporalType.TIMESTAMP)
: 实体类会封装成完整的时间yyyy-MM-dd hh:MM:ss
的 Date 类型。
1.10 @Enumerated
用于直接映射枚举类型的字段。
public @interface Enumerated {
EnumType value() default EnumType.ORDINAL;
}
1.11 @Lob
@Lob
将属性映射为数据库支持的大对象类型,支持以下两种数据库类型的字段。
-
Clob
:长字符串类型,java.sql.Clob
、Character[]
、char[]
、String
都将被映射成Clob
类型。 -
Blob
:字节类型,java.sql.Blob
、Byte[]
、byte[]
、实现了 Serializable 接口类型都将被映射成Blob
类型。
2. JPA 中的实体关系
简单地用原始字段持久化一个对象只是等式的一半。JPA 还具有管理彼此相关的实体的能力。表和对象中都可能存在四种实体关系:
- 一对多
- 多对一
- 多对多
- 一对一
2.1 @JoinColumn
定义外键关联的字段名称。
public @interface JoinColumn {
//注解所在当前表的主键名,必须写
String name() default "";
//关联外部表的列名,默认是外部主键名
String referencedColumnName() default "";
//外键字段是否唯一
boolean unique() default false;
//外键字段是否允许为空
boolean nullable() default true;
//是否跟随一起新增
boolean insertable() default true;
//是否跟随一起更新
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
}
配合 @OneToOne
、@OneToMany
、@ManyToOne
一起使用。
2.2 关系映射注解
public @interface OneToOne {
//关系目标实体,默认为该字段的类型
Class targetEntity() default void.class;
//级联操作策略
CascadeType[] cascade() default {};
//数据获取方式,立即加载和延迟加载
FetchType fetch() default FetchType.EAGER;
boolean optional() default true;
//关联关系被谁维护,一般不需要特别指定, 只有关系维护方才能操作两者的关系,被维护方即使设置了维护方属性进行存储也不会更新外键关联
//mappedBy不能与@JoinColumn或者@JoinTable同时使用
//mappedBy的值是指另一方的实体里属性的字段,而不是数据库字段,也不是实体的对象的名字,是另一方配置了@JoinColumn或者@JoinTable注解的属性的字段名称
String mappedBy() default "";
//是否级联删除,和 CascadeType.REMOVE 的效果一样,只是配置了两种中的一种就会自动级联删除
boolean orphanRemoval() default false;
}
public enum CascadeType {
ALL,
PERSIST,
MERGE,
REMOVE,
REFRESH
}
级联操作策略代码举例解释
public class Student {
@ManyToMany(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
private Set courses = new HashSet<>();
}
- CascadeType.PERSIST 级联新建:若 Student 实体持有的 Course 实体在数据库中不存在时,Student 保存时自动在 Course 实体对应的数据库中保存 Course 数据。
- CascadeType.MERGE 级联更新:当 Student 中的数据改变,会相应地更新 Course 中的数据。
- CascadeType.REMOVE 级联删除:删除 Student 实体,与它有映射关系的 Course 实体也会跟着被删除。
- CascadeType.REFRESH 级联刷新:Student 保存时重新加载 Course 关系
- CascadeType.DETACH 级联脱离:要删除一个实体,直接撤销所有相关的外键关联
- CascadeType.ALL 拥有以上所有级联操作权限
- 默认,关系表不会产生任何影响
@OneToOne
需要配合 @JoinColumn 一起使用
在使用@OneToOne
进行双向关联时,需要在类上加上注解 @JsonIdentityInfo
,这个注解被用来在序列化/反序列化时为该对象或字段添加一个对象识别码,通常是用来解决循环嵌套的问题。通过配置属性 generator 来确定识别码生成的方式,配置属性 property 来确定识别码的名称,识别码名称没有限制。
一般这个注解可以这么加
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
@OneToMany
和 @ManyToOne
同上。
2.3 @OrderBy
用于关联查询时排序。
@Entity
public class Course {
...
@ManyToMany
@OrderBy("lastname ASC")
public List getStudents() {...};
...
}
@Entity
public class Student {
...
@ManyToMany(mappedBy="students")
@OrderBy //默认使用主键排序
public List getCourses() {...};
...
}
3. 查询
注意: 这里是接口,是
persistence-api
包中的,项目里Repository
里的接口上面实现的@Query
注解不是下面这个,spring-data-jpa
的查询和解析留待下回分解
/**
* Interface used to control query execution.
*
* @since Java Persistence 1.0
*/
public interface Query {
/**
* Execute a SELECT query and return the query results
* as a List.
* @return a list of the results
* @throws IllegalStateException if called for a Java
* Persistence query language UPDATE or DELETE statement
*/
public List getResultList();
/**
* Execute a SELECT query that returns a single result.
* @return the result
* @throws NoResultException if there is no result
* @throws NonUniqueResultException if more than one result
* @throws IllegalStateException if called for a Java
* Persistence query language UPDATE or DELETE statement
*/
public Object getSingleResult();
/**
* Execute an update or delete statement.
* @return the number of entities updated or deleted
* @throws IllegalStateException if called for a Java
* Persistence query language SELECT statement
* @throws TransactionRequiredException if there is
* no transaction
*/
public int executeUpdate();
/**
* Set the maximum number of results to retrieve.
* @param maxResult
* @return the same query instance
* @throws IllegalArgumentException if argument is negative
*/
public Query setMaxResults(int maxResult);
/**
* Set the position of the first result to retrieve.
* @param startPosition the start position of the first result, numbered from 0
* @return the same query instance
* @throws IllegalArgumentException if argument is negative
*/
public Query setFirstResult(int startPosition);
/**
* Set an implementation-specific hint.
* If the hint name is not recognized, it is silently ignored.
* @param hintName
* @param value
* @return the same query instance
* @throws IllegalArgumentException if the second argument is not
* valid for the implementation
*/
public Query setHint(String hintName, Object value);
/**
* Bind an argument to a named parameter.
* @param name the parameter name
* @param value
* @return the same query instance
* @throws IllegalArgumentException if parameter name does not
* correspond to parameter in query string
* or argument is of incorrect type
*/
public Query setParameter(String name, Object value);
/**
* Bind an instance of java.util.Date to a named parameter.
* @param name
* @param value
* @param temporalType
* @return the same query instance
* @throws IllegalArgumentException if parameter name does not
* correspond to parameter in query string
*/
public Query setParameter(String name, Date value, TemporalType temporalType);
/**
* Bind an instance of java.util.Calendar to a named parameter.
* @param name
* @param value
* @param temporalType
* @return the same query instance
* @throws IllegalArgumentException if parameter name does not
* correspond to parameter in query string
*/
public Query setParameter(String name, Calendar value, TemporalType temporalType);
/**
* Bind an argument to a positional parameter.
* @param position
* @param value
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to positional parameter of query
* or argument is of incorrect type
*/
public Query setParameter(int position, Object value);
/**
* Bind an instance of java.util.Date to a positional parameter.
* @param position
* @param value
* @param temporalType
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to positional parameter of query
*/
public Query setParameter(int position, Date value, TemporalType temporalType);
/**
* Bind an instance of java.util.Calendar to a positional parameter.
* @param position
* @param value
* @param temporalType
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to positional parameter of query
*/
public Query setParameter(int position, Calendar value, TemporalType temporalType);
/**
* Set the flush mode type to be used for the query execution.
* The flush mode type applies to the query regardless of the
* flush mode type in use for the entity manager.
* @param flushMode
*/
public Query setFlushMode(FlushModeType flushMode);
}