Hibernate 表映射 主键生成策略与复合主键
Posted 小猩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate 表映射 主键生成策略与复合主键相关的知识,希望对你有一定的参考价值。
主要分析三点:
二、单一主键映射和主键的生成策略 ;
三、复合主键的表映射 ;
Hibernate封装了数据库DDL语句,只需要将数据表和类之间实现映射,即可对数据表进行操作。
示例:数据库中存在表interface_admin.ds_area,实现表和类之间映射,其中单一主键oggKeyId,使用主键自动生成策略UUID,具体第二点进行阐述 。
package com.pec.model; import java.io.Serializable; import java.sql.Timestamp; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; @Entity @Table(name = "interface_admin.ds_area") @org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true) public class DsAreaModel implements Serializable { private static final long serialVersionUID = 1L; //电商平台代号(WS微商/CT村淘/TM天猫/JD京东) private String comId ; //行政省/直辖市代号 private String provinceId ; //行政省/直辖市名称 private String provinceName ; //地级市代号 private String cityId ; //地级市名称 private String cityName ; //行政区/县代号 private String regiId ; //行政区/县名称 private String regiName ; //创建时间 private Timestamp creatDate ; //最后更新时间 private Timestamp lastUpdDate ; //主键 private String oggKeyId ; @Column(name = "com_id") public String getComId() { return comId; } public void setComId(String comId) { this.comId = comId; } @Column(name = "province_id") public String getProvinceId() { return provinceId; } public void setProvinceId(String provinceId) { this.provinceId = provinceId; } @Column(name = "province_nm") public String getProvinceName() { return provinceName; } public void setProvinceName(String provinceName) { this.provinceName = provinceName; } @Column(name = "city_id") public String getCityId() { return cityId; } public void setCityId(String cityId) { this.cityId = cityId; } @Column(name = "city_nm") public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } @Column(name = "regi_id") public String getRegiId() { return regiId; } public void setRegiId(String regiId) { this.regiId = regiId; } @Column(name = "regi_nm") public String getRegiName() { return regiName; } public void setRegiName(String regiName) { this.regiName = regiName; } @Column(name = "cre_date") public Timestamp getCreatDate() { return creatDate; } public void setCreatDate(Timestamp creatDate) { this.creatDate = creatDate; } @Column(name = "last_upd_date") public Timestamp getLastUpdDate() { return lastUpdDate; } public void setLastUpdDate(Timestamp lastUpdDate) { this.lastUpdDate = lastUpdDate; } @Id @Column(name = "ogg_key_id", unique = true, nullable = false) @GeneratedValue(generator = "systemUUID") @GenericGenerator(name = "systemUUID", strategy = "uuid") public String getOggKeyId() { return oggKeyId; } public void setOggKeyId(String oggKeyId) { this.oggKeyId = oggKeyId; } }
二、单一主键映射和主键的生成策略
当数据表中只存在单一主键(大多数情况下都是单一主键),主键标识着一条记录,不可重复和为空,标志位唯一。但是此主键不需要手动输入,而在Hibernate下包含有主键的生成策略。例如第一点的示例中:
@Id @Column(name = "ogg_key_id", unique = true, nullable = false) @GeneratedValue(generator = "systemUUID") @GenericGenerator(name = "systemUUID", strategy = "uuid") public String getOggKeyId() { return oggKeyId; } public void setOggKeyId(String oggKeyId) { this.oggKeyId = oggKeyId; }
此时,只需要在相应的setter的方法上,设置主键的生成策略(本例中为UUID)Hibernate即可自动生成唯一性标识,而省去了手动输入的麻烦。使用Hibernate映射主键总结几点:
1、为了保证对象标识符的唯一性与不可变性,应该让Hibernate来为主键赋值,而不是程序。
2、Hibernate中唯一一种最简单通用的主键生成器就是:UUID。虽然是个32位难读的长字符串,但是它没有跨数据库的问题,将来切换数据库极其简单方便,推荐使用。
3、Hibernate下的UUID生成和Java下的UUID生成有所不同,Hibernate下是32位字长的16进制数,而Java下的则是36位字长。
4、其他主键的生成策略:assigned、increment、hilo、seqhilo、sequence、identity、native、guid、foreign、select。详解参考:http://www.cnblogs.com/kakafra/archive/2012/09/16/2687569.html
三、复合主键的表映射 (出现情况不多,不推荐使用复合主键)
复合主键的情况是数据表存在多个主键,在实现与类映射时,情况比单一主键更加复杂。通常情况都会想法设法修改表结构成为单一主键,绕开复合主键,所以不推荐使用。但最近在做项目的时候,遇到表结构是复合主键,也无法绕开的情况,所以按此思路开始。这里我使用的是将主键属性封装在一个类当中,其中要注意的几点:
1. 使用复合主键的实体类必须实现Serializable接口。
必须实现Serializable接口的原因很简单,我们查找数据的时候是根据主键查找的。打开Hibernate的帮助文档我们可以找到get与load方法的声明形式如下:
Object load(Class theClass,Serializable id)
Object get(Class theClass,Serializable id)
当我们查找复合主键类的对象时,需要传递主键值给get()或load()方法的id参数,而id参数只能接收一个实现了Serializable接口的对象。而复合主键类的主键不是一个属性可以表示的,所以只能先new出复合主键类的实例(例如:new People()),然后使用主键属性的set方法将主键值赋值给主键属性,然后将整个对象传递给get()或load()方法的id参数,实现主键值的传递,所以复合主键的实体类必须实现Serializable接口。
2. 使用复合主键的实体类必须重写equals和hashCode方法。必须重写equals和hashCode方法也很好理解。这两个方法使用于判断两个对象(两条记录)是否相等的。为什么要判断两个对象是否相等呢?因为数据库中的任意两条记录中的主键值是不能相同的,所以我们在程序中只要确保了两个对象的主键值不同就可以防止主键约束违例的错误出现。也许这里你会奇怪为什么不使用复合主键的实体类不重写这两个方法也没有主键违例的情况出现,这是因为使用单一主键方式,主键值是Hibernate来维护的,它会确保主键不会重复,而复合主键方式,主键值是编程人员自己维护的,所以必须重写equals和hashCode方法用于判断两个对象的主键是否相同。
3. 重写的equals和hashCode方法,只与主键属性有关,普通属性不要影响这两个方法进行判断。这个原因很简单,主键才能决定一条记录,其他属性不能决定一条记录。
4.主键类必须有默认的public无参数的构造方法。
实现复合主键映射的三种方式:
1、@Embeddable + @Id + @Embedded(@Embeddable 表示这个类可以嵌入到别的类中去,常以表示其他类的某个属性。)
2、@Embeddable + @EmbeddedId( @Embedded 它和 @Embeddable 正好相反,它用来表示某个属性是被嵌入进来的。)
3、@IdClass + @Id(@EmbeddedId = @Embedded + @Id)
以下贴出第一种方式的代码:
主键类ModelKey:
package com.pec.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class ModelKey implements Serializable{ private static final long serialVersionUID = 8099372586856509841L; // 接口类型 private String intType; // 条目识别码 private String recordId; // private String createTimeStamp; public String getIntType() { return intType; } public void setIntType(String intType) { this.intType = intType; } public String getRecordId() { return recordId; } public void setRecordId(String recordId) { this.recordId = recordId; } public String getCreateTimeStamp() { return createTimeStamp; } public void setCreateTimeStamp(String createTimeStamp) { this.createTimeStamp = createTimeStamp; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((createTimeStamp == null) ? 0 : createTimeStamp.hashCode()); result = prime * result + ((intType == null) ? 0 : intType.hashCode()); result = prime * result + ((recordId == null) ? 0 : recordId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ModelKey other = (ModelKey) obj; if (createTimeStamp == null) { if (other.createTimeStamp != null) return false; } else if (!createTimeStamp.equals(other.createTimeStamp)) return false; if (intType == null) { if (other.intType != null) return false; } else if (!intType.equals(other.intType)) return false; if (recordId == null) { if (other.recordId != null) return false; } else if (!recordId.equals(other.recordId)) return false; return true; } public ModelKey(String intType, String recordId, String createTimeStamp) { this.intType = intType; this.recordId = recordId; this.createTimeStamp = createTimeStamp; } public ModelKey() { } }
实现类InterFaceDataModel:
package com.pec.model; import java.io.Serializable; import java.sql.Timestamp; import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; import com.sun.tracing.dtrace.Attributes; @Entity @Table(name = "interface_admin.interface_data_test") @org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true) //@IdClass(ModelKey.class) public class InterFaceDataModel implements Serializable{ private static final long serialVersionUID = 8586209694356988171L; private ModelKey modelKey ; private String seniorRecordId ; private Timestamp daleteTime ; private String createUser ; private String oprStatus ; private String oprUser ; private String oprTimeStamp ; private String yyyymmdd ; private String selKey1 ; private String selKey2 ; private String selKey3 ; private String selKey4 ; private String valList ; @Id @Embedded @AttributeOverrides({ @AttributeOverride(name="intType", column = @Column(name="int_type")), @AttributeOverride(name="recordId", column = @Column(name="record_id")), @AttributeOverride(name="createTimeStamp", column = @Column(name="create_timestamp")) }) public ModelKey getModelKey() { return modelKey; } public void setModelKey(ModelKey modelKey) { this.modelKey = modelKey; } @Column(name = "senior_record_id") public String getSeniorRecordId() { return seniorRecordId; } public void setSeniorRecordId(String seniorRecordId) { this.seniorRecordId = seniorRecordId; } @Column(name = "delete_time") public Timestamp getDaleteTime() { return daleteTime; } public void setDaleteTime(Timestamp daleteTime) { this.daleteTime = daleteTime; } @Column(name = "create_user") public String getCreateUser() { return createUser; } public void setCreateUser(String createUser) { this.createUser = createUser; } @Column(name = "opr_status") public String getOprStatus() { return oprStatus; } public void setOprStatus(String oprStatus) { this.oprStatus = oprStatus; } @Column(name = "opr_user") public String getOprUser() { return oprUser; } public void setOprUser(String oprUser) { this.oprUser = oprUser; } @Column(name = "opr_timestamp") public String getOprTimeStamp() { return oprTimeStamp; } public void setOprTimeStamp(String oprTimeStamp) { this.oprTimeStamp = oprTimeStamp; } @Column(name = "yyyymmdd") public String getYyyymmdd() { return yyyymmdd; } public void setYyyymmdd(String yyyymmdd) { this.yyyymmdd = yyyymmdd; } @Column(name = "sel_key1") public String getSelKey1() { return selKey1; } public void setSelKey1(String selKey1) { this.selKey1 = selKey1; } @Column(name = "sel_key2") public String getSelKey2() { return selKey2; } public void setSelKey2(String selKey2) { this.selKey2 = selKey2; } @Column(name = "sel_key3") public String getSelKey3() { return selKey3; } public void setSelKey3(String selKey3) { this.selKey3 = selKey3; } @Column(name = "sel_key4") public String getSelKey4() { return selKey4; } public void setSelKey4(String selKey4) { this.selKey4 = selKey4; } @Column(name = "val_list") public String getValList() { return valList; } public void setValList(String valList) { this.valList = valList; } }
具体参考链接:
http://blog.csdn.net/handsomelinux/article/details/50575877
http://www.cnblogs.com/otomedaybreak/archive/2012/01/25/2329390.html
以上是关于Hibernate 表映射 主键生成策略与复合主键的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate:复合主键 - 外键:如何在两个表之间映射各个字段
JavaEE持久层框架对比与hibernate主键生成策略总结