ID生成策略:主键手工设定很不方便,在我们实际工作中在MySQL里面用自增字段auto increment,在oracel中一般用sequence。所以把表建成auto increment,对于类里面对象的对应的值就不能指定了,得靠程序或数据库自动生成,hibernate或JPA就实现了这样的功能,我们可以通过设置告诉这个字段怎么生成,这样写程序的时候就不用设定了。这个就叫ID的生成策略。
动手实验:
使用xml时,常用<generator class="native"></generator>
native
-
根据底层数据库的能力选择
identity
,sequence
或者hilo
中的一个。
identity
-
对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是
long
,short
或者int
类型的。 sequence
-
在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是
long
,short
或者int
类型的。
使用annotation,使用注解@GeneratedValue默认值是auto相当于xml里面的native
@SequenceGenerator(name="teacherSEQ", sequenceName="teacherSEQ_DB")
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@TableGenerator
联合主键:假设sutdent的id和name是它的主键。单独写一个类作为学生的主键类StudentPK.java,在主键类里面必须要重写equals、hashCode方法,实现serializable接口(为什么?),serializable把当前对象序列化,这样就可以直接写到硬盘上,也可以直接读出来,也可以直接传送。为什么要序列化呢?作为Student这个对象来说,它在数据库表里可能存在多条记录,如果把这多条记录放到内存里就是多个Student对象,每个对象都有一个主键StudentPK对象。系统做集群,好多个服务器,如果这台服务器当机了,可以把这台服务器里的对象传给另外一台服务器,就需要实现序列化,但是这种情况并不多见。还有一种情况,加入内存满了,可以使用虚拟内存(把硬盘上一块空间作为内存使用)。这种情况下就可以把序列化了的那一部分内容先暂时放到硬盘上去。主键类为什么要重写equals和hashCode呢?是为了保证唯一性,不仅 在数据库中保证唯一性,我们还要把数据放到内存中,好多student对象,里面都有自己的studentpK,那么每个对象之间怎么区分开来?数据库里面用主键做区分,那么内存里面也应该用这种逻辑来做区分,不然和数据库内容就不匹配了,所以用联合主键就应该重写equals和hashCode。从数据库的角度想,主键相同就返回true,从内存角度想主键相同就是id和name相同。为什么重写hashCode呢?如果我们的对象装到了hash表里面,查找里面的对象,首先是查找hashcode。所以最终代码如下:
package hjj.lch.hibernate.model; import java.io.Serializable; public class StudentPK implements Serializable{ private int id; private String name; 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; } @Override public boolean equals(Object obj){ if(obj instanceof StudentPK){ StudentPK pk = (StudentPK)obj; if(this.id == pk.getId() && this.name.equals(pk.getName())){ return true; } } return false; } @Override public int hashCode(){ return this.name.hashCode(); } }
在Student.java里面就不用写id和name了,但是需要记录一个主键类的对象,这样才能唯一的记录当前的student。
package hjj.lch.hibernate.model; public class Student { private StudentPK pk; private int age; // 年龄 public StudentPK getPk() { return pk; } public void setPk(StudentPK pk) { this.pk = pk; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
配置文件里面表名主键,组件作为联合标志符
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- 以下是表的映射, 此处若不写 table="student" , 则表示实体类名字和表名一样,数据库表名捕区分大小写--> <class name="hjj.lch.hibernate.model.Student"> <!-- 以下为字段的映射 --> <composite-id name="pk" class="hjj.lch.hibernate.model.StudentPK"> <key-property name="id"></key-property> <key-property name="name" length="16"></key-property> </composite-id> <!-- 普通属性 --> <property name="age"></property> </class> </hibernate-mapping>
一开始利用HibernateExportUtil在控制台生成的建表语句在Mysql Commend Client中执行,会出现以下错误
Specified key was too long; max key length is 767 bytes。意思就是主键太长了.解决办法在student.hbm.xml文件中设置那两个字段的长度,所以加了length="16"。
下面说annotation的联合主键用法,将主键类TeacherPK.java注为@Embeddable,并且把主键的属性注解为@Id
package hjj.lch.hibernate.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class TeacherPK implements Serializable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name="name", length=16) public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj){ if(obj instanceof TeacherPK){ TeacherPK pk = (TeacherPK)obj; if(this.id == pk.getId() && this.name.equals(pk.getName())); return true; } return false; } @Override public int hashCode(){ return this.name.hashCode(); } }
报错Specified key was too long; max key length is 767 bytes的时候限制字段长度就好, @Column(name="name", length=16)。
package hjj.lch.hibernate.model; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class Teacher { private TeacherPK pk; private String title; // 职称 @Id public TeacherPK getPk() { return pk; } public void setPk(TeacherPK pk) { this.pk = pk; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
这是第一种方法,下面做第二种方法是在Teacher.java中将teacherpk组件注解为@EmbeddedId。TeacherPK.java中就不用注解了
package hjj.lch.hibernate.model; import java.io.Serializable; import javax.persistence.Column; public class TeacherPK implements Serializable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name="name", length=16) public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj){ if(obj instanceof TeacherPK){ TeacherPK pk = (TeacherPK)obj; if(this.id == pk.getId() && this.name.equals(pk.getName())); return true; } return false; } @Override public int hashCode(){ return this.name.hashCode(); } }
package hjj.lch.hibernate.model; import javax.persistence.EmbeddedId; import javax.persistence.Entity; @Entity public class Teacher { private TeacherPK pk; private String title; // 职称 @EmbeddedId public TeacherPK getPk() { return pk; } public void setPk(TeacherPK pk) { this.pk = pk; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
再做第三种将类注解为@IdClass,并将该实体类中所有属于主键的属性都注解为@Id,TeacherPK.java里面就不用写那些了。
package hjj.lch.hibernate.model; import java.io.Serializable; import javax.persistence.Column; public class TeacherPK implements Serializable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } @Column(name="name", length=16) public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj){ if(obj instanceof TeacherPK){ TeacherPK pk = (TeacherPK)obj; if(this.id == pk.getId() && this.name.equals(pk.getName())); return true; } return false; } @Override public int hashCode(){ return this.name.hashCode(); } }
package hjj.lch.hibernate.model; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; @Entity @IdClass(TeacherPK.class) public class Teacher { private int id; private String name; private String title; // 职称 @Id public int getId() { return id; } public void setId(int id) { this.id = id; } @Id public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
第二种和第三种比较常用,但是联合主键就不常用!!!哈哈