Hibernate学习笔记(三)Hibernate生成表单ID主键生成策略
一、 Xml方式
<id>标签必须配置在<class>标签内第一个位置。由一个字段构成主键,如果是复杂主键<composite-id>标签
被映射的类必须定义对应数据库表主键字段。大多数类有一个JavaBeans风格的属性, 为每一个实例包含唯一的标识。<id> 元素定义了该属性到数据库表主键字段的映射。
<id
name="propertyName" (1)
type="typename" (2)
column="column_name" (3)
unsaved-value="null|any|none|undefined|id_value" (4)
access="field|property|ClassName" (5)
node="element-name|@attribute-name|element/@attribute|.">
<generatorclass="generatorClass"/>
</id>
(1) name (可选): 标识属性的名字(实体类的属性)。
(2) type (可选): 标识Hibernate类型的名字(省略则使用hibernate默认类型),也可以自己配置其它hbernate类型(integer, long, short, float,double, character, byte, boolean, yes_no, true_false)
(2) length(可选):当type为varchar时,设置字段长度
(3) column (可选 - 默认为属性名): 主键字段的名字(省略则取name为字段名)。
(4) unsaved-value (可选 - 默认为一个切合实际(sensible)的值): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。 这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注) 但未再次持久化的实例区分开来。
(5) access (可选 - 默认为property): Hibernate用来访问属性值的策略。
如果 name属性不存在,会认为这个类没有标识属性。
unsaved-value 属性在Hibernate3中几乎不再需要。
还有一个另外的<composite-id>定义可以访问旧式的多主键数据。 我们强烈不建议使用这种方式。
<generator>元素(主键生成策略)
主键生成策略是必须配置
用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用<param>元素来传递。
<id name="id"type="long" column="cat_id">
<generator class="org.hibernate.id.TableHiLoGenerator">
<param name="table">uid_table</param>
<param name="column">next_hi_value_column</param>
</generator>
</id>
所有的生成器都实现org.hibernate.id.IdentifierGenerator接口。 这是一个非常简单的接口;某些应用程序可以选择提供他们自己特定的实现。当然, Hibernate提供了很多内置的实现。下面是一些内置生成器的快捷名字:
increment
用于为long, short或者int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。
identity
对DB2,MySQL, MS SQL Server,Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是long, short 或者int类型的。 (数据库自增)
sequence
在DB2,PostgreSQL, Oracle, SAPDB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。(数据库自增)
hilo
使用一个高/低位算法高效的生成long, short 或者 int类型的标识符。给定一个表和字段(默认分别是 hibernate_unique_key和next_hi)作为高位值的来源。 高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
seqhilo
使用一个高/低位算法来高效的生成long, short 或者 int类型的标识符,给定一个数据库序列(sequence)的名字。
uuid
用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串,它的生成是由hibernate生成,一般不会重复。
UUID包含:IP地址,JVM的启动时间(精确到1/4秒),系统时间和一个计数器值(在JVM中唯一)。 在Java代码中不可能获得MAC地址或者内存地址,所以这已经是我们在不使用JNI的前提下的能做的最好实现了
guid
在MS SQL Server 和 MySQL 中使用数据库生成的GUID字符串。
native
根据底层数据库的能力选择identity,sequence 或者hilo中的一个。(数据库自增)
assigned
让应用程序在save()之前为对象分配一个标示符。这是 <generator>元素没有指定时的默认生成策略。(如果是手动分配,则需要设置此配置)
select
通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。
foreign
使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。
二、 annotateon方式
使用@GeneratedValue(strategy=GenerationType)注解可以定义该标识符的生成策略
Strategy有四个值:
① 、AUTO- 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.
相当于native
② 、TABLE- 使用表保存id值
③ 、IDENTITY- identity column
④ 、SEQUENCE- sequence
注意:auto是默认值,也就是说没有后的参数则表示为auto
1、AUTO默认
@Id
@GeneratedValue
public int getId() {
return id;
}
或
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return id;
}
1、 对于mysql,使用auto_increment
2、 对于oracle使用hibernate_sequence(名称固定)
2、IDENTITY
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return id;
}
对DB2,MySQL, MS SQL Server,Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是long, short 或者int类型的。 (数据库自增)
注意:此生成策略不支持Oracle
3、SEQUENCE
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
public int getId() {
return id;
}
在DB2,PostgreSQL,Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。(数据库自增)
注意:此生成策略不支持MySQL
4、为Oracle指定定义的Sequence
a)、首先需要在实体类前面申明一个Sequence如下:
方法:@SequenceGenerator(name="SEQ_Name",sequenceName="SEQ_DB_Name")
参数注意:SEQ_Name:表示为申明的这个Sequence指定一个名称,以便使用
SEQ_DB_Name:表示为数据库中的Sequence指定一个名称。
两个参数的名称可以一样。
@Entity
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
public class Teacher {
……
}
b)、然后使用@GeneratedValue注解
方法:@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SEQ_Name")
参数:strategy:固定为GenerationType.SEQUENCE
Generator:在实体类前面申明的sequnce的名称
@Entity
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
public class Teacher {
private int id;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
public int getId() {
return id;
}}
5、TABLE - 使用表保存id值
原理:就是在数据库中建立一个表,这个表包含两个字段,一个字段表示名称,另一个字段表示值。每次在添加数据时,使用第一个字段的名称,来取值作为添加数据的ID,然后再给这个值累加一个值再次存入数据库,以便下次取出使用。
Table主键生成策略的定义:
@javax.persistence.TableGenerator(
name="Teacher_GEN", //生成策略的名称
table="GENERATOR_TABLE", //在数据库生成表的名称
pkColumnName = "pk_key", //表中第一个字段的字段名 类型为varchar,key
valueColumnName = "pk_value", //表中第二个字段的字段名 int ,value
pkColumnValue="teacher", //这个策略中使用该记录的第一个字段的值(key值)
initialValue = 1, //这个策略中使用该记录的第二个字段的值(value值)初始化值
allocationSize=1 //每次使用数据后累加的数值
)
这样执行后,会在数据库建立一个表,语句如下:
create tableGENERATOR_TABLE (pk_key varchar(255),pk_value integer )
结构:
并且表建立好后,就插入了一个记录,如下:
注:这条记录的pk_value值为2,是因为刚刚做例程序时,已经插入一条记录了。初始化时为1。
使用TABLE主键生成策略:
@Entity
@javax.persistence.TableGenerator(
name="Teacher_GEN", //生成策略的名称
table="GENERATOR_TABLE", //在数据库生成表的名称
pkColumnName = "pk_key", //表中第一个字段的字段名 类型为varchar,key
valueColumnName = "pk_value", //表中第二个字段的字段名 int ,value
pkColumnValue="teacher", //这个策略中使用该记录的第一个字段的值(key值)
initialValue = 1, //这个策略中使用该记录的第二个字段的值(value值)初始化值
allocationSize=1 //每次使用数据后累加的数值
)
public class Teacher {
private int id;
@Id
@GeneratedValue(strategy=GenerationType.TABLE,generator="Teacher_GEN")
public int getId() {
return id;}}
注意:这样每次在添加Teacher记录时,都会先到GENERATOR_TABLE表取pk_key=teacher的记录后,使用pk_value值作为记录的主键。然后再给这个pk_value字段累加1,再存入到GENERATOR_TABLE表中,以便下次使用。
这个表可以给无数的表作为主键表,只是添加一条记录而以(需要保证table、pkColumnName、valueColumnName三个属性值一样就可以了。),这个主键生成策略可以跨数据库平台。
三、 联合主键
复合主键(联合主键):多个字段构成唯一性。
1、xml方式
a) 实例场景:核算期间
// 核算期间
public class FiscalYearPeriod {
private int fiscalYear; //核算年
private int fiscalPeriod; //核算月
private Date beginDate; //开始日期
private Date endDate; //结束日期
private String periodSts; //状态
public int getFiscalYear() {
return fiscalYear;
}
public void setFiscalYear(int fiscalYear) {
this.fiscalYear = fiscalYear;
}
public int getFiscalPeriod(){ return fiscalPeriod;}
public void setFiscalPeriod(int fiscalPeriod) {
this.fiscalPeriod =fiscalPeriod;
}
public DategetBeginDate() {return beginDate;}
public void setBeginDate(DatebeginDate) { this.beginDate = beginDate; }
public Date getEndDate(){return endDate;}
public void setEndDate(DateendDate) { this.endDate = endDate; }
public StringgetPeriodSts() { return periodSts;}
public voidsetPeriodSts(String periodSts) {this.periodSts = periodSts;}
}
复合主键的映射,一般情况把主键相关的属性抽取出来单独放入一个类中。而这个类是有要求的:必需实现序列化接口(java.io.Serializable)(可以保存到磁盘上),为了确定这个复合主键类所对应对象的唯一性就会产生比较,对象比较就需要复写对象的hashCode()、equals()方法(复写方法如下图片),然后在类中引用这个复合主键类
b) 复合主键类:
复合主键必需实现java.io.Serializable接口
public class FiscalYearPeriodPKimplements java.io.Serializable {
private int fiscalYear;//核算年
private int fiscalPeriod;//核算月
public int getFiscalYear() {
return fiscalYear;
}
public void setFiscalYear(int fiscalYear) {
this.fiscalYear = fiscalYear;
}
public int getFiscalPeriod(){
return fiscalPeriod;
}
public void setFiscalPeriod(int fiscalPeriod) {
this.fiscalPeriod =fiscalPeriod;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime* result + fiscalPeriod;
result = prime* result + fiscalYear;
return result;
}
@Override
public boolean equals(Object obj){
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() !=obj.getClass())
return false;
FiscalYearPeriodPKother = (FiscalYearPeriodPK) obj;
if (fiscalPeriod != other.fiscalPeriod)
return false;
if (fiscalYear != other.fiscalYear)
return false;
return true;
}}
c) 实体类:(中引用了复合主键类)
public class FiscalYearPeriod{
private FiscalYearPeriodPK fiscalYearPeriodPK;//引用 复合主键类
private Date beginDate;//开始日期
private Date endDate;//结束日期
private String periodSts;//状态
public FiscalYearPeriodPK getFiscalYearPeriodPK() {
return fiscalYearPeriodPK;
}
public void setFiscalYearPeriodPK(FiscalYearPeriodPKfiscalYearPeriodPK) {
this.fiscalYearPeriodPK = fiscalYearPeriodPK;
}
………………
d) FiscalYearPeriod.hbm.xml映射文件
<hibernate-mapping>
<class name="com.bjsxt.hibernate.FiscalYearPeriod"table="t_fiscal_year_period">
<composite-id name="fiscalYearPeriodPK">
<key-property name="fiscalYear"/>
<key-property name="fiscalPeriod"/>
</composite-id>
<property name="beginDate"/>
<property name="endDate"/>
<property name="periodSts"/>
</class>
</hibernate-mapping>
e) 导出数据库输出SQL语句:
create table t_fiscalYearPeriod (fiscalYear integer not null, fiscalPeriodinteger not null, beginDate datetime, endDate datetime, periodSts varchar(255),primary key (fiscalYear, fiscalPeriod))//实体映射到数据就是两个字段构成复合主键
f) 数据库表结构:
g) 复合主键关联映射数据存储:
session =HibernateUtils.getSession();
tx =session.beginTransaction();
FiscalYearPeriod fiscalYearPeriod = new FiscalYearPeriod();
//构造复合主键
FiscalYearPeriodPK pk = new FiscalYearPeriodPK();
pk.setFiscalYear(2009);
pk.setFiscalPeriod(11);
fiscalYearPeriod.setFiscalYearPeriodPK(pk);//为对象设置复合主键
fiscalYearPeriod.setEndDate(new Date());
fiscalYearPeriod.setBeginDate(new Date());
fiscalYearPeriod.setPeriodSts("Y");
session.save(fiscalYearPeriod);
h) 执行输出SQL语句:
Hibernate: insert into t_fiscalYearPeriod (beginDate, endDate, periodSts,fiscalYear, fiscalPeriod) values (?, ?, ?, ?, ?)
注:如果再存入相同复合主键的记录,就会出错。
i) 数据的加载:
数据加载非常简单,只是主键是一个对象而以,不是一个普通属性。
2、annotation方式
下面是定义组合主键的几种语法:
将组件类注解为@Embeddable,并将组件的属性注解为@Id
将组件的属性注解为@EmbeddedId
将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id
a) 将组件类注解为@Embeddable,并将组件的属性注解为@Id
组件类:
@Embeddable
public class TeacherPK implementsjava.io.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(Stringname) { this.name = name;}
@Override
public boolean equals(Object o) { ……}
@Override
public int hashCode() { return this.name.hashCode(); }
}
将组件类的属性注解为@Id,实体类中组件的引用
@Entity
public class Teacher {
private TeacherPK pk;
private String title;
@Id
public TeacherPK getPk(){
return pk;
}}
b) 将组件的属性注解为@EmbeddedId
注意:只需要在实体类中表示复合主键属性前注解为@Entity,表示此主键是一个复合主键
注意了,复合主键类不需要任何的注意。
@Entity
public class Teacher {
private TeacherPK pk;
private String title;
@EmbeddedId
public TeacherPK getPk(){
return pk;
}}
c) 类注解为@IdClass,主键的属性都注解为@Id
需要将复合主键类建立好,不需要进行任何注解
在实体类中不需要进行复合主键类的引用
需要在实体类前面注解为@IdClass,并且指定一个value属性,值为复合主键类的class
需要在实体类中进行复合主键成员属性前面注解为@Id
如下:
@Entity
@IdClass(TeacherPK.class)
public class Teacher {
//private TeacherPK pk;//不再需要
private int id;
private String name;
@Id
public int getId() {return id; }
public void setId(int id) { this.id = id; }
@Id
public String getName() {return name;}
public void setName(Stringname) {this.name = name;
}}
Hibernate学习笔记(三)Hibernate生成表单ID主键生成策略的更多相关文章
- hibernate学习笔记(4)表单操作
User.hbm.xml的表单配置: ①主键 <id name="id" type="java.lang.Integer"> <column ...
- 分库分布的几件小事(四)分库分表的id主键生成
1.问题 其实这是分库分表之后你必然要面对的一个问题,就是id咋生成?因为要是分成多个表之后,每个表都是从1开始累加,那肯定不对啊,需要一个全局唯一的id来支持.所以这都是你实际生产环境中必须考虑的问 ...
- Django学习笔记(五)—— 表单
疯狂的暑假学习之 Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path ...
- [原创]java WEB学习笔记85:Hibernate学习之路-- -映射 一对一关系 ,基于主键方式实现
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Flutter学习笔记(13)--表单组件
如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...
- ng2 学习笔记(二)表单及表单验证
在上一篇文章中提到了表单,只说了表单的数据绑定,这一篇文章主要讲一下表单验证,为什么把表单单独拿出来学习,主要是因为,表单是商业应用的支柱,我们用它来执行登录.求助.下单.预订机票.安排会议,以及不计 ...
- SQL学习笔记三之MySQL表操作
阅读目录 一 存储引擎介绍 二 表介绍 三 创建表 四 查看表结构 五 数据类型 六 表完整性约束 七 修改表ALTER TABLE 八 复制表 九 删除表 一 存储引擎介绍 存储引擎即表类型,mys ...
- Hibernate的ID主键生成策略
ID生成策略(一) 通过XML配置实现ID自己主动生成(測试uuid和native) 之前我们讲了除了通过注解的方式来创建一个持久化bean外.也能够在须要持久化的bean的包路径下创建一个与bean ...
- 4.ID主键生成策略
保证唯一性(auto_increment) 一.xml方式 <?xml version="1.0"?> <!DOCTYPE hibernate-mapping P ...
随机推荐
- C#图片切割、图片压缩、缩略图生成
C#图片切割.图片压缩.缩略图生成的实现代码 /// 图片切割函数 /// </summary> /// <param name="sourceFile"&g ...
- BZOJ 2228 礼物(gift)(最大子长方体)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2228 题意:给出一个只含有NP两种字母的长方体.从中找出只含有字母N的长方体,造型为a* ...
- 对于json对像,怎么遍历json对象的所有key,在使用json对象时,如果无法知道key,怎么通过key变量来获取值
对于json对像,怎么遍历json对象的所有key,在使用json对象时,如果无法知道key,怎么通过key变量来获取值?请参阅下面的关键代码: <html> <head> & ...
- 【Todo】CSDN的《问底》系列-学习
看到CSDN的这个系列<问底>,看各篇文章的题目感觉不错.好好学习下: http://www.csdn.net/tag/%E9%97%AE%E5%BA%95/news
- 【分享】哪个OS X版本支持哪个Xcode的版本?
在安装Xcode时,会碰到跟OS X操作系统匹配的问题,对照下下面几个表,以免给自己带来编译不过或者奇怪的错误等问题 以下列表来自网络: Xcode 1.0 - Xcode 2.x (before i ...
- HDU 1253 (简单三维广搜) 胜利大逃亡
奇葩!这么简单的广搜居然爆内存了,而且一直爆,一直爆,Orz 而且我也优化过了的啊,尼玛还是一直爆! 先把代码贴上睡觉去了,明天再来弄 //#define LOCAL #include <ios ...
- 【英语】Bingo口语笔记(60) - 口语中的浊化发音
- Android WebView中那些不得不解决的坑~~
前面那张hybrid开发心得 有人问 怎么解决不用onJsPrompt 来回调js函数的问题.其实很简单,就是在在你的jscalljava回调函数内 另外开个线程去load js代码即可: wb.po ...
- unity, surface shader access world position and localposition
一,surface shader中访问worldposition 在surface shader中访问世界坐标,只需在Input结构体中声明float3 worldPos即可,如下: struct ...
- Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://weizhulin.blog.51cto.com/1556324/311450 大 ...