Hibernate Annotation即hibernate注解,可以通过另一种方式将持久化类转化成表的相关信息,可以简化hibernate的配置文件。本文主要对Hibernate的注解进行讲解,由于篇幅原因,将注解部分分为两篇文章来写。集合映射和关联关系映射将在后面一文讲解。本文包括以下五个部分:
- 基础映射。
- 主键映射。
- 基本属性映射。
- 复合属性映射。
- 继承映射。
一、基础映射(注解加在持久化类上面)
1.1到1.4的注解都是JPA的注解,1.5是hibernate的注解。
1.1 @Entity: 将POJO转化成持久化类。
1.2 @Table: 把持久化类转化成表的相关信息,@Table注解当中有以下几个属:
- name: 指定表名。
- schema: 指定将数据表存入哪个数据库。
- catalog: 指定将数据表存入哪个数据库。
- indexes: 指定表的引索列.
- uniqueConstraints: 指定唯一约束。
1.3 indexes : @Index(columnList="数据表中的列名", name="索引名")。用于创建表的索引。
indexes={@Index(columnList="name", name="IDX_NAME"),
@Index(columnList="address", name="IDX_ADDRESS")}
1.4 uniqueConstraints : @UniqueConstraint(columnNames={"列名","列名"}, name="唯一约束名")。用于多列建立联合唯一约束。
uniqueConstraints={@UniqueConstraint(columnNames={"name", "age"}, name="UC_NAME_AGE")})
1.5 hibernate注解
- @DynamicInsert:动态插入,根据持久化对象的属性是否有值明确生成insert语句。
- @DynamicUpdate:动态修改,它会判断持久化对象中属性,哪些属性值发生了改变就会生成update的语句。(持久化状态下做修改)
- @SelectBeforeUpdate:修改之前先查询,查询得到持久化对象再与脱管状态下的对象进行比较,哪些属性值发生了改变就会生成update的语句。(脱管状态下做修改)
例如:User实体类
package edu.scut.a_BasicMapping;
import javax.persistence.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
@Entity//将POJO类转化成持久化类
@Table(name="USER_INFO",//指定表名
catalog="day33b",//指定创建到哪个数据库
//schema="day33b",//指定创建到哪个数据库,和catalog指定一个即可
indexes={@Index(columnList="name",name="IDX_NAME"),
@Index(columnList="address",name="IDX_ADDRESS")},//创建表的索引
uniqueConstraints={@UniqueConstraint(columnNames={"name","age"},name="UC_NAME_AGE")}) //多列联合唯一约束
//三个hibernate注解
//@DynamicInsert(true) //动态插入,根据持久化对象的属性是否有值,生成相应的Sql语句
//@DynamicUpdate(true) //动态修改,会判断持久化对象中的属性,那些属性改变,才会生成相应的update语句(持久化状态下做修改)
@SelectBeforeUpdate(true) //修改之前先进行查询,查询得到持久化对象与脱管状态下的对象进行比较,那些属性改变生成sql语句。
public class User {
@Id
private int id;
private String name;
private int age;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
生成的表user_info信息:
二、主键映射
2.1 主键生成策略
@GeneratorValue(strategy=GenerationType.xxx)
- GenerationType.AUTO:让Hibernate根据数据库方言自动选择主键生成策略。
- GenerationType.IDENTITY: 适宜MySQL、SqlServer有自增长列的数据库。
- GenerationType.SEQUENCE:适宜Oracle这种没有自增长有sequence的数据库。
- GenerationType.TABLE: 适宜所有的数据库,因为它会单独生成一张表来维护主键生成。
例如:User.实体类
package edu.scut.b_PrimaryKeyMapping.copy;
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
@Entity//将POJO类转化成持久化类
@Table(name="USER_INFO")//指定表名
public class User{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private int age;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
生成的表user_info信息:
2.2 单个属性做主键: 在指定的属性上加@Id。
2.3 多个属性做联合主键。
- 在多个属性上加@Id。
- 这个持久化类必须实现Serializale接口。
例如:Person类的firstName和lastName两个属性要做联合主键,那么这两个属性上面都要加@Id注解,并且Person类要是实现Serializale接口。
Person实体类:
package edu.scut.b_PrimaryKeyMapping;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class Person implements Serializable {
@Id
private String firstName;
@Id
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.4 复合属性做联合主键。
- 在复合属性上加:@EmbeddedId。
- 复合属性类必须实现Serializale接口。
例如:Employee实体类中,name属性是一个复合属性,要是以name属性作为主键,那么name属性上要加@Embedded注解,Name类要实现Serializale接口。
Employee类:
package edu.scut.b_PrimaryKeyMapping;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class Employee implements Serializable {
@EmbeddedId
private Name name;
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Name类:
package edu.scut.b_PrimaryKeyMapping;
import java.io.Serializable;
public class Name implements Serializable{
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
三、基本属性映射
3.1 @Column : 持久化类中属性转化成数据库表中列的相关信息。
- name:指定列名。
- length: 该列支持的长度。
- precision:有效的总位数。(BigDecimal)。
- scale:小数点的位数。(BigDecimal)。
- unique: 唯一约束。
- nullable:非空约束。
- insertable:是否允许插入true:允许 false: 不允许。
- updatable:是否允许修改true:允许 false: 不允许。
- columnDefinition :指定列的定义。
例如:User类
package edu.scut.c_BasicFieldMapping;
import java.io.Serializable;
import java.math.BigDecimal;
import javax.persistence.*;
import org.hibernate.type.TrueFalseType;
@Entity//将POJO类转化成持久化类
@Table(name="USER_INFO")//指定表名
public class User{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="U_ID")
private int id;
@Column(name="U_NAME",//列名
length=20, //长度
nullable=false, //非空约束
unique=false //唯一约束
)
private String name;
@Column(name="U_AGE",columnDefinition="int(10) NOT NULL default 20")
private int age;
@Column(name="U_ADD",
insertable=false, //允许插入
updatable=false //允许修改
)
private String address;
@Column(name="U_SALARY",
precision=6, //小数的总位数
scale=2)//小数点后面的位数
private BigDecimal salary;
public int getId() {
return id;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
生成的表user_info信息:
3.2 @Lob: 映射大的二进制数或者文本。
3.3 @Temporal:修饰日期类型Date。
- TemporalType.DATE : yyyy-MM-dd。
- TemporalType.TIME : HH:mm:ss。
- TemporalType.TIMESTAMP : yyyy-MM-dd HH:mm:ss。
3.4 @Transient:指定不是持久化属性。
例如:Employee实体类
package edu.scut.c_BasicFieldMapping;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
@Entity
@Table(name="EMP_INFO")
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="EMP_ID")
private int id;
@Column(name="EMP_NAME")
private String name;
@Column(name="EMP_PIC")
@Lob
private byte[] picture;
@Column(name="EMP_BIRTH")
@Temporal(TemporalType.TIMESTAMP)
private Date birthday;
@Transient
private String remark;
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte[] getPicture() {
return picture;
}
public void setPicture(byte[] picture) {
this.picture = picture;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
生成的表emp_info信息:
四、复合属性映射
4.1 @Embedded:用于修饰复合属性(内含的)。
例如:Employee类中的name属性是复合属性,要用@Embedded注解修饰。
Employee实体类:
package edu.scut.d_MultiFieldMapping;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Embedded //复合属性(将主键类的属性直接应用过来)
private Name name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Name实体类:
package edu.scut.d_MultiFieldMapping;
import java.io.Serializable;
import javax.persistence.Column;
public class Name implements Serializable {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
注意:复合属性的列名可以重命名,有两种方式。
4.2 @AttributeOverrides:第一种属性重新命名。在复合属性的上面加此注解。
@AttributeOverrides({@AttributeOverride(name="firstName", column=@Column(name="F_NAME")),
@AttributeOverride(name="lastName", column=@Column(name="L_NAME"))})
例如:Employee实体类
package edu.scut.d_MultiFieldMapping;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Embedded //复合属性(将主键类的属性直接应用过来)
//改变复合属性的名称(第一种方式)
@AttributeOverrides({@AttributeOverride(name="firstName",column=@Column(name="F_NAME")),
@AttributeOverride(name="lastName",column=@Column(name="L_NAME"))})
private Name name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.3 第二种属性重命名方式:复合属性类的属性上面直接加@Column注解,给出列名。
例如:Name实体类
package edu.scut.d_MultiFieldMapping;
import java.io.Serializable;
import javax.persistence.Column;
public class Name implements Serializable {
@Column(name="F_NAME") //改变复合属性名称的第二种方式
private String firstName;
@Column(name="L_NAME")
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
五、继承映射
当持久化类存在继承关系时,就可以用继承映射。继承映射提供了三种策略:
5.1 第一种方式(SINGLE_TABLE):所有子类中属性都生成到父类表中(一张表)。
注意:所有子类属性中不能加非空约束。
5.1.1 父类
- @Entity @Table(name="PER_INFO")。指定表名。
- @Inheritance(strategy=InheritanceType.SINGLE_TABLE)。生成一张表。
- @DiscriminatorColumn(name="DC", discriminatorType=DiscriminatorType.INTEGER) 。辨别者列,用来分辨每一行的信息对应的是哪个类的数据。
- @DiscriminatorValue("1") 。辨别者列值,即每一个类的辨别者的不同代号。
父类:Person
package edu.scut.g_ExtendsMapping2; import javax.persistence.*; @Entity @Table(name="PER_INFO") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) //只生成一张表 @DiscriminatorColumn(name="DC",discriminatorType=DiscriminatorType.INTEGER) //辨别者列 @DiscriminatorValue("1") //辨别者列的值 public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
5.1.2 所有子类
- @Entity。
- @DiscriminatorValue("2")。指定辨别者列值。
子类:Employee
子类:Managerpackage edu.scut.g_ExtendsMapping2; import javax.persistence.*; @Entity @DiscriminatorValue("2") //辨别者列的值 public class Employee extends Person{ private float salary; public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } }
package edu.scut.g_ExtendsMapping2; import javax.persistence.*; @Entity @DiscriminatorValue("3") //辨别者列 public class Manager extends Employee{ private String job; public String getJob() { return job; } public void setJob(String job) { this.job = job; } }
这三个类生成了一张表:
per_info表
5.2 第二种方式(JOINED):所有的子类与父类都会单独生成表(子类表的中主键列同时也是外键列,它引用顶级父类表中的主键列)。
注意:查询时会出现很多join语句。
5.2.1 父类
- @Entity @Table(name="PER_INFO")。
- @Inheritance(strategy=InheritanceType.JOINED)。
父类:Person
5.2.2 子类package edu.scut.g_ExtendsMapping1; import javax.persistence.*; @Entity @Table(name="PER_INFO") @Inheritance(strategy=InheritanceType.JOINED) //会生成多张表,几个持久化类就生成几张表 public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
- @Entity @Table(name="")。
子类:Employee
package edu.scut.g_ExtendsMapping1; import javax.persistence.Entity; @Entity public class Employee extends Person{ private float salary; public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } }
子类:Manager生成的三张表信息:package edu.scut.g_ExtendsMapping1; import javax.persistence.Entity; @Entity public class Manager extends Employee{ private String job; public String getJob() { return job; } public void setJob(String job) { this.job = job; } }
per_info表
employee表
manager表
5.3 第三种方式(TABLE_PER_CLASS):所有的子类与父类都会单独生成表,子类会把父类中的属性继承过来生成在自己的表中。
注意:这种策略主键不能用自增长,查询时会出现union运算。
5.3.1 父类
- @Entity @Table(name="PER_INFO")。
- @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)。
父类:Person
package edu.scut.g_ExtendsMapping3; import javax.persistence.*; @Entity @Table(name="PER_INFO") @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Person { @Id //@GeneratedValue(strategy=GenerationType.AUTO) 这种策略的ID不能自增长 private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
5.3.2 子类
- @Entity @Table(name="")。
子类:Employee
package edu.scut.g_ExtendsMapping3; import javax.persistence.Entity; @Entity public class Employee extends Person{ private float salary; public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } }
子类:Manager
生成的三张表信息:package edu.scut.g_ExtendsMapping3; import javax.persistence.Entity; @Entity public class Manager extends Employee{ private String job; public String getJob() { return job; } public void setJob(String job) { this.job = job; } }
per_info表
employee表
manager表