Hibernate 提供了三种方式将POJO变成PO类
通常情况下如果实体类的标识属性是基本数据类型、基本类型的包装类、String、Date等类型,可以简单的使用@ID修饰该实体的属性即可。
如果希望Hibernate为逻辑主键自动生成主键值,可以使用@GeneratedValue来修饰实体的标识属性。
属性 | 是否必须 | 说明 |
strategy | 否 | 指定Hibernate对该主键列使用怎么样的主键生成策略
|
generator | 否 | 当使用GenerationType.SEQUENCE,GenerationType.TABLE主键生成策略时,该属性引用@SequenceGenerator,@TableGenerator所定义的生成器的名称 |
JPA注解只支持AUTO、Identity、SEQUENCE、TABLE这4中生成策略,如果希望使用Hibernate提供的主键生成策略,就需要使用Hibernate本身的@GenericGenerator注解,该注解用于定义生成器。包括name和strategy两个属性。
stratety属性可指定的值:
// 消息类的标识属性 @Id @Column(name="news_id") // 使用@GenericGenerator定义主键生成器。 // 该主键生成器名为fk_hilo,使用Hibernate的hilo策略, @GenericGenerator(name="fk_hilo" , strategy="hilo") // 指定使用fk_hilo主键生成器 @GeneratedValue(generator="fk_hilo") private Integer id;
<hibernate-mapping> <class name="com.songxu.modle.Person" table="person"> <id column="id" name="id" type="int"> <generator class="increment"/> </id> <!-- column同名时可以省略 --> <property column="name" generated="never" lazy="false" name="name" type="string"/> <property column="age" generated="never" lazy="false" name="age" type="int"/> <property column="registertime" generated="never" lazy="false" name="time" type="date"/> </class> </hibernate-mapping>
<id column="id" name="id" type="string"> <generator class="uuid"></generator>
List是有序集合,因此持久化到数据库时也必须增加一列来表示集合的次序。
以下Person类 添加了集合属性list用于保存学校的名称
@Id @Column(name="perosn_id") @GeneratedValue(strategy=GenerationType.IDENTITY) // 标识属性 private Integer id; private String name; private int age; // 集合属性,保留该对象关联的学校 @ElementCollection(targetClass=String.class) // 映射保存集合属性的表 @CollectionTable(name="school_inf", // 指定表名为school_inf joinColumns=@JoinColumn(name="person_id" , nullable=false)) // 指定保存集合元素的列为 school_name @Column(name="school_name") // 映射集合元素索引的列 @OrderColumn(name="list_order") private List<String> schools = new ArrayList<>();生成的表后,List集合属性的表总是以外键列和元素索引列作为联合主键
Set是无序集合,因此无需使用@OrderColumn注解映射集合元素的索引列。
// 集合属性,保留该对象关联的学校 @ElementCollection(targetClass=String.class) // 映射保存集合属性的表 @CollectionTable(name="school_inf", // 指定表名为school_inf joinColumns=@JoinColumn(name="person_id" , nullable=false)) // 指定保存集合元素的列为 school_name,nullable=false增加非空约束 @Column(name="school_name" , nullable=false) private Set<String> schools = new HashSet<>();
Map属性需要使用@MapKeyColumn映射保存Map Key的数据列
// 集合属性,保留该对象关联的考试成绩 @ElementCollection(targetClass=Float.class) // 映射保存集合属性的表 @CollectionTable(name="score_inf", // 指定表名为score_inf joinColumns=@JoinColumn(name="person_id" , nullable=false)) @MapKeyColumn(name="subject_name") // 指定Map key的类型为String类型 @MapKeyClass(String.class) // 映射保存Map value的数据列 @Column(name="mark") private Map<String , Float> scores = new HashMap<>();
如果注解与Person类定义的泛型指定的类型不一致时,Hibernate将通过注解类型进行数据库表的生成工作。当插入数据时,会抛出数据类型不匹配的异常。
生成的保存Map数据的数据表将使用外键列和Map中的 key作为联合主键
组件属性是指持久化类的属性不是基本数据类型,也不是字符串、日期等标量类型,而是一个复合类型的。
下面是一个组件的示例。定义了一个Name类型,使用@Embeddable注解,该注解与@Entity类似。该类包含一个owner属性,该属性指向包含该Name属性的实体。为了告诉Hibernate这个owner属性不是普通属性,而是包含Name组件的Person实体,可使用@Parent注解修饰该属性。
@Embeddable public class Name { // 定义first成员变量 @Column(name="person_firstname") private String first; // 定义last成员变量 @Column(name="person_lastname") private String last; // 引用拥有该Name的Person对象 @Parent // ① private Person owner; // 无参数的构造器 public Name() { } // 初始化全部成员变量的构造器 public Name(String first , String last) { this.first = first; this.last = last; } // first的setter和getter方法 public void setFirst(String first) { this.first = first; } public String getFirst() { return this.first; } // last的setter和getter方法 public void setLast(String last) { this.last = last; } public String getLast() { return this.last; } // owner的setter和getter方法 public void setOwner(Person owner) { this.owner = owner; } public Person getOwner() { return this.owner; } }
@Id @Column(name="person_id") @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private int age; // 组件属性name private Name name;
这种方式无需使用@Embeddable注解修饰,而是直接在持久化类中使用@Embedded注解修饰组件属性
public class Name { // 定义first成员变量 private String first; // 定义last成员变量 private String last; // 引用拥有该Name的Person对象 @Parent private Person owner; // 无参数的构造器 public Name() { } // 初始化全部成员变量的构造器 public Name(String first , String last) { this.first = first; this.last = last; } // first的setter和getter方法 public void setFirst(String first) { this.first = first; } public String getFirst() { return this.first; } // last的setter和getter方法 public void setLast(String last) { this.last = last; } public String getLast() { return this.last; } // owner的setter和getter方法 public void setOwner(Person owner) { this.owner = owner; } public Person getOwner() { return this.owner; } }
@Embedded @AttributeOverrides({ @AttributeOverride(name="first", column = @Column(name="person_firstname")), @AttributeOverride(name="last", column = @Column(name="person_lastname")) }) private Name name;
如果组件包含了 list map set集合,可以直接在组件类中使用@ElementCollection修饰集合属性,并使用@CollectionTable指定保存集合属性的属性表。
@Embeddable public class Name { // 定义first成员变量 @Column(name="person_firstname") private String first; // 定义last成员变量 @Column(name="person_lastname") private String last; // 引用拥有该Name的Person对象 @Parent private Person owner; // 集合属性,保留该对象关联的考试成绩 @ElementCollection(targetClass=Integer.class) @CollectionTable(name="power_inf", joinColumns=@JoinColumn(name="person_name_id" , nullable=false)) @MapKeyColumn(name="name_aspect") @Column(name="name_power" , nullable=false) @MapKeyClass(String.class) private Map<String , Integer> power = new HashMap<>(); // 无参数的构造器 public Name() { } }
使用组件作为复合主键,也就是使用组件作为持久化类的标识符,则该组件类必须满足以下要求。
public class Name implements java.io.Serializable { // 定义first成员变量 private String first; // 定义last成员变量 private String last; // 无参数的构造器 public Name() { } // 初始化全部成员变量的构造器 public Name(String first , String last) { this.first = first; this.last = last; } // first的setter和getter方法 public void setFirst(String first) { this.first = first; } public String getFirst() { return this.first; } // last的setter和getter方法 public void setLast(String last) { this.last = last; } public String getLast() { return this.last; } // 重写equals()方法,根据first、last进行判断 public boolean equals(Object obj) { if (this == obj) { return true; } if (obj != null && obj.getClass() == Name.class) { Name target = (Name)obj; return target.getFirst().equals(getFirst()) && target.getLast().equals(getLast()); } return false; } // 重写hashCode()方法,根据first、last计算hashCode值 public int hashCode() { return getFirst().hashCode() * 31 + getLast().hashCode(); } }
// 以Name组件作为标识属性 @EmbeddedId @AttributeOverrides({ // 指定 @AttributeOverride(name="first", column = @Column(name="person_firstname")), @AttributeOverride(name="last", column = @Column(name="person_lastname")) }) private Name name;
Hibernate 还提供了另一种联合主键支持,如果需要直接将持久化类的多列映射成联合主键,则该持久化类必须满足如下条件。
@Entity @Table(name="person_inf") public class Person implements java.io.Serializable { // 定义first属性,作为标识属性的成员 @Id private String first; // 定义last属性,作为标识属性的成员 @Id private String last; private int age; // first的setter和getter方法 public void setFirst(String first) { this.first = first; } public String getFirst() { return this.first; } // last的setter和getter方法 public void setLast(String last) { this.last = last; } public String getLast() { return this.last; } // age的setter和getter方法 public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } // 重写equals()方法,根据first、last进行判断 public boolean equals(Object obj) { if (this == obj) { return true; } if (obj != null && obj.getClass() == Person.class) { Person target = (Person)obj; return target.getFirst().equals(getFirst()) && target.getLast().equals(getLast()); } return false; } // 重写hashCode()方法,根据first、last计算hashCode值 public int hashCode() { return getFirst().hashCode() * 31 + getLast().hashCode(); } }