基于 hibernate-jpa-2.1-api ,mysql数据库
import javax.persistence.*;
一、JPA 基本注解:
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(generator="h-uuid2")
@GenericGenerator(name = "h-uuid2",strategy="uuid2")
private String id;
@Column(name="user_name")
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
@Transient
private String temp;
...
}
----
create table t_user (
id varchar(255) not null,
password varchar(255),
regDate date,
user_name varchar(255),
primary key (id)
) engine=InnoDB
1、@Entity -- 表示实体类
说明这个类是实体类,并且使用默认的orm规则(类名即表名,类属性名即表字段名)。如果改变这种默认就使用:
@Table 改变class名与表名的映射规则,@Column 改变class中字段名与db中表的字段名的映射规则。
2、@Table -- 标识实体类表名
当实体类名和数据库表名不一致时使用 @Table 标注说明,即使表名一致,也推荐使用,提高程序的可读性 。该标注与 @Entity 标注并列使用。
属性名 |
释义 |
值 |
默认值 |
name |
指定数据库表名称 若不指定则以实体类名称作为表名 |
字符串 |
“” |
schema |
指定该实体映射的schema |
字符串 |
“” |
catalog |
与schema属性相同 |
字符串 |
“” |
indexes |
索引 |
@Index |
{} |
uniqueConstraints |
唯一约束 |
@UniqueConstraint |
{} |
3、@Id -- 标记属性的主键
一旦标注了主键,该实体属性的值可以指定,也可以根据一些特定的规则自动生成。(一个实体中可以出现多个@Id注解,但需要@IdClass配合使用,以表示联合主键(不推荐))。
3.1 @Id -- 标识数据类型
分类 |
类型 |
Java基本数据类型 |
byte、int、short、long、char |
Java基本数据类型对应的封装类 |
Byte、Integer、Short、Long、Character |
大数值型类 |
java.math.BigInteger |
字符串类型 |
String |
时间日期型 |
java.util.Date、java.sql.Date |
double 和 float浮点类型和它们对应的封装类不能作为主键,因为判断是否唯一是通过equals方法来判断的,不能够准确的匹配。
3.2 @GeneratedValue -- 标注主键的生成策略
属性名 |
释义 |
值 |
默认值 |
strategy |
主键的生成策略 |
GenerationType.TABLE 通过表产生主键,框架借由表模拟序列产生主键 GenerationType.SEQUENCE 通过序列产生主键(不支持MySql) GenerationType.IDENTITY 自增长(不支持Oracle) GenerationType.AUTO 自动选择合适的策略 |
GenerationType.AUTO |
generator |
自定义生成策略 |
字符串(对应@GenericGenerator注解的name属性值) |
“” |
需要注意的是,同一张表中自增列最多只能有一列,GenerationType.SEQUENCE在oracle数据库时使用,配合@SequenceGenerator指定使用哪个序列名(后续使用)
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) //针对mysql数据库:自增长
private int id;
----
@Id
@GeneratedValue(strategy=GenerationType.AUTO) //根据数据库,自动选择合适的策略
private int id;
3.3 @GenericGenerator -- 自定义主键生成策略
属性名 |
释义 |
值 |
默认值 |
name |
生成器名称 |
字符串(对应@GeneratedValue注解的generator属性值) |
无 |
strategy |
具体生成器的类名 |
见该表下的代码块 |
无 |
parameters |
strategy生成器用到的参数 |
{} |
@Id
@GeneratedValue(generator="h-uuid2") //自定义str: 和name值对应
@GenericGenerator(name = "h-uuid2",strategy="uuid2") //自定义策略: uuid2
private String id;
主键生成策略和各自的具体生成器之间的关系,在org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory中指定如下:
四种数据库的支持情况如下:
数据库名称 |
支持的id策略 |
mysql |
GenerationType.TABLE |
oracle |
strategy=GenerationType.AUTO |
postgreSQL |
GenerationType.TABLE |
kingbase |
GenerationType.TABLE |
4、@Column -- 标识实体类中属性与数据表中字段的对应关系。
属性名 |
释义 |
值 |
默认值 |
name |
所对应表字段的名称 |
字符串 |
“” |
unique |
是否为唯一标识(亦可在@Table注解中设置) |
布尔值 |
false |
nullable |
是否可为null值 |
布尔值 |
true |
insertable |
在使用’insert’时,是否插入该字段的值 |
布尔值 |
true |
updatable |
在使用’update’时,是否更新该字段的值 |
布尔值 |
true |
columnDefinition |
通过Entity生成DDL语句 |
字符串 |
“” |
table |
包含当前字段的表名 |
字符串 |
“” |
length |
字段长度(类型仅为varchar时生效) |
正整数或零 |
255 |
precision |
数值的总长度(类型仅为double时生效) |
正整数或零 |
0 |
scale |
保留小数点后数值位数(类型仅为double时生效) |
正整数或零 |
0 |
提示:此注解可以标注在getter方法或属性前。
5、 @Temporal -- 指明该属性获取时间精度
默认为 TemporalType.TIMESTAMP 类型。
类型 |
说明 |
java.sql.Date |
日期型,精确到年月日,例如“2008-08-08” |
java.sql.Time |
时间型,精确到时分秒,例如“20:00:00” |
java.sql.Timestamp |
时间戳,精确到纳秒,例如“2008-08-08 20:00:00.000000001” |
//@Temporal(TemporalType.DATE) //表中类型: date
//@Temporal(TemporalType.TIMESTAMP) //表中类型: datetime
@Temporal(TemporalType.TIME) //表中类型: time
private Date regDate;
6、@Transient -- 属性不与表字段映射
一旦变量被transient修饰,属性将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问(即:不与表字段映射)。 常用于某属性仅为临时变量时。
7、@Basic
表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的属性,默认即为 @Basic。
属性名 |
释义 |
值 |
默认值 |
fetch |
加载方式 |
FetchType.EAGER 即时加载 FetchType.LAZY 延迟加载 |
FetchType.EAGER |
strategy |
是否可为null |
布尔值 |
true |
hibernate 的xml配置默认为:懒加载, JPA 注释配置默认为:立即加载。
对于一些特殊的属性,比如长文本型text、字节流型blob型的数据,在加载Entity时,这些属性对应的数据量比较大,有时创建实体时如果也加载的话,可能严重造成资源的占用。要想解决这些问题,此时就可设置实体属性的加载方式为延迟加载(LAZY)
二、JPA 映射注解:
1、单向多对一关联
多个角色对应一个用户。 多:添加一的类对象关联属性;一:不做变化
注意:注解 @ManyToOne(fetch=FetchType.EAGER) 默认的是立即加载,需要懒加载的时候,修改fetch参数
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")
private User user; //关联属性
...
}
-----
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
...
}
2、单向一对多的关联
一个用户对应多个角色。 一:添加多的类对象集合关联属性;多:不做变化
注意:注解@OneToMany(fetch=FetchType.LAZY)默认的是懒加载,需要立即加载的时候,修改fetch参数
删除1这端的记录时,可以删除,然后会把多端的外键设置为null,需要级联删除可以设置@OneToMany(设置cascade属性)
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
@OneToMany(fetch=FetchType.LAZY,cascade= {CascadeType.REMOVE})
@JoinColumn(name="user_id")
private Set<Role> roles = new HashSet<>();
...}
----
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
...}
3、双向的一对多(多对一)的关联
一这端:user,多这端:role
注意:
1)双向关联关系,两遍默认都会维护关系,可能冲突,也影响效率,正常情况关系交给“多”这端维护,一这端配置mappedBy属性则放弃@OneToMany(mappedBy="user")值为多这端关联属性的属性名
2)一旦一这端使用 mappedBy 属性,那么@JoinColumn这个注解就不能使用了,用了会出错
3)需要级联操作可以设置@OneToMany(设置cascade属性),不设置放弃维护的这端删除不了
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
//mappedBy="user" 一这端放弃维护关联关系, 值为多这端关联属性的属性名
@OneToMany(fetch=FetchType.LAZY,cascade= {CascadeType.ALL},mappedBy="user")
private Set<Role> roles = new HashSet<>();
...}
----
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
@ManyToOne(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST,CascadeType.MERGE})
@JoinColumn(name="user_id")
private User user;
...}
4、双向的一对一的关联
双向关联,需要一边要放弃关系维护
注意:
1)负责维护关系的一端,要配置唯一约束 unique=true,因为一对一关联,两边都是唯一的
2) 默认关联策略是:立即加载
3)需要级联操作可以设置@OneToOne(设置cascade属性),不设置放弃维护的这端删除不了
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
@OneToOne(mappedBy="user",cascade= {CascadeType.ALL})
private Role role;
...}
----
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
@OneToOne
@JoinColumn(name="user_id",unique=true)
private User user;
...}
5、双向多对多的关联
双向关联,需要一边要放弃关系维护
注意:
1) 默认关联策略是:立即加载
2)需要级联操作可以设置@ManyToMany(设置cascade属性),不设置放弃维护的这端删除不了
3) 关联中间表,无法自定义字段,不灵活,
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
@ManyToMany(mappedBy="users",cascade=CascadeType.ALL)
private Set<Role> roles = new HashSet<>();
...}
----
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
@ManyToMany
@JoinTable(name="t_user_role",
joinColumns = {@JoinColumn(name="t_user",referencedColumnName="id")},
inverseJoinColumns = {@JoinColumn(name="t_role",referencedColumnName="id")}
)
private Set<User> users = new HashSet<>();
...}
注意:在真项目开发中,处理双向多对多的关联,一般变通来处理,将对对多关联,转换为两个一对多的关联,中间表可以自定义字段。
转换为两个双向一对多实例
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@Temporal(TemporalType.DATE) //表中类型: date
private Date regDate;
@OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private Set<UserRole> userRoles = new HashSet<>();
...}
----
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="role_name")
private String roleName;
private String state;
@OneToMany(mappedBy="role",cascade=CascadeType.ALL)
private Set<UserRole> userRoles = new HashSet<>();
...}
--中间表--
@Entity
@Table(name="t_user_role")
public class UserRole {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private Date createDate;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="user_id")
private User user;
@ManyToOne
@JoinColumn(name="role_id")
private Role role;
...}
注意:
1) 需要级联操作可以设置@OneToMany(设置cascade属性),不设置放弃维护的这端删除不了
2) 关联中间表,可自定定义字段,
end...