Hibernate4教程二:基本配置(3)

被映射的类必须定义对应数据库表主键字段。大多数类有一个JavaBeans风格的属性, 为每一个实例包含唯一的标识。<id> 元素定义了该属性到数据库表主键字段的映射。

java代码:
  1. <id  
  2. name="propertyName" (1)  
  3. type="typename" (2)  
  4. column="column_name" (3)  
  5. unsaved-value="null|any|none|undefined|id_value" (4)  
  6. access="field|property|ClassName"> (5)  
  7. <generator class="generatorClass"/>  
  8. </id>  
(1) name (可选): 标识属性的名字
(2) type (可选): 标识Hibernate类型的名字
(3) column (可选 - 默认为属性名): 主键字段的名字
(4) unsaved-value (可选 - 默认为一个切合实际(sensible)的值): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。 unsaved-value 属性在Hibernate4中几乎不再需要。
(5) access (可选 - 默认为property):Hibernate用来访问属性值得策略
Hibernate的类型
Hibernate在进行映射的时候,既不使用Java的类型,也不使用数据库的类型,而是使用自己提供的类型, Hibernate提供大量的内建类型,也支持自定义类型。
 
Hibernate的内建类型
内置的 basic mapping types 可以大致地分类为:
1:integer, long, short, float, double, character, byte, boolean, yes_no, true_false
这些类型都对应Java的原始类型或其封装类,来符合特定厂商的SQL 字段类型。
2:boolean,yes_no和true_false
是Java中boolean或者Boolean的另外说法。
3:string
从 java.lang.String 到 VARCHAR(或者 Oracle 的 VARCHAR2)的映射。
4:date, time, timestamp
从java.util.Date和其子类到SQL类型 DATE,TIME 和 TIMESTAMP(或等价类型)的映射。
5:calendar, calendar_date
从java.util.Calendar到SQL类型TIMESTAMP和DATE(或等价类型)的映射。
6:big_decimal, big_integer
从 java.math.BigDecimal 和 java.math.BigInteger 到 NUMERIC(或者 Oracle 的 NUMBER类型)的映射。
7:locale, timezone, currency
从 java.util.Locale,java.util.TimeZone 和 java.util.Currency 到 VARCHAR(或者 Oracle 的VARCHAR2 类型)的映射。Locale 和 Currency 的实例被映射为它们的 ISO 代码。TimeZone 的实例被影射为它的 ID。
8:class
从java.lang.Class 到 VARCHAR(或者 Oracle 的 VARCHAR2 类型)的映射。Class 被映射为它的全限定名。
9:binary
把字节数组(byte arrays)映射为对应的 SQL 二进制类型。
10:text
把长 Java 字符串映射为 SQL 的 CLOB 或者 TEXT 类型。
11:serializable
把可序列化的 Java 类型映射到对应的 SQL 二进制类型。你也可以为一个并非默认为基本类型的可序列化 Java 类或者接口指定 Hibernate 类型 serializable。
12:clob, blob
JDBC 类 java.sql.Clob 和 java.sql.Blob的映射。某些程序可能不适合使用这个类型,因为blob 和 clob 对象可能在一个事务之外是无法重用的。(而且, 驱动程序对这种类型的支持充满着补丁和前后矛盾。)
13:imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary
一般来说,映射类型被假定为是可变的 Java 类型,只有对不可变 Java 类型,Hibernate 会采取特定的优化措施,应用程序会把这些对象作为不可变对象处理。比如,你不应该对作为 imm_timestamp 映射的 Date 执行 Date.setTime()。要改变属性的值,并且保存这一改变,应用程序必须对这一属性重新设置一个新的(不一样的)对象。
 
在 org.hibernate.Hibernate 中,定义了基础类型对应的 Type 常量。比如,Hibernate.STRING 代表 string 类型。
ncomposite-id元素
如果表使用联合主键,你可以映射类的多个属性为标识符属性。这种做法现在是非常不推荐的,但可能有些遗留系统使用了双主键或多主键。
配置如下示例:

java代码:
  1. <composite-id>  
  2. <key-property name=“name"/>  
  3. <key-property name="deptment"/>  
  4. </composite-id>  
就表示是一个双主键,由name和deptment联合来做主键
 
使用Composite-id元素的时候,你的持久化类必须覆盖 equals() 和 hashCode() 方法,来实现组合的标识符的相等判断。实现Serializable 接口也是必须的。
 
可选的<generator>子元素是一个Java类的名字,用来为该持久化类的实例生成唯一的标识。如果这个生成器实例需要某些配置值或者初始化参数, 用<param>元素来传递。
如下示例:

java代码:
  1. <id name="id" type="long" column="person_id">  
  2. <generator class="sequence">  
  3. <param name="sequence">person_id_sequence</param>  
  4. </generator>  
  5. </id>  

下面是一些Hibernate内置生成器(ID生成策略):
increment
用于为long, short或者int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。
identity
对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是long, short 或者int类型的。
Sequence
在DB2,PostgreSQL, Oracle, SAP DB, 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进制数字的字符串。
guid
在MS SQL Server 和 MySQL 中使用数据库生成的GUID字符串
native
根据底层数据库的能力选择identity, sequence 或者hilo中的一个。
Assigned
让应用程序在save()之前为对象分配一个标示符。这是 <generator>元素没有指定时的默认生成策略。
select
通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。
foreign
使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用
推荐使用UUID
UUID 包含:IP 地址、JVM 的启动时间(精确到 1/4 秒)、系统时间和一个计数器值(在 JVM 中唯一)。

java代码:
  1. <property>元素为类定义了一个持久化的,JavaBean风格的属性。   
  2. <property   
  3.     name="propertyName" (1)   
  4.     column="column_name" (2)   
  5.     type="typename" (3)   
  6.     update="true|false" (4)   
  7.     insert="true|false" (5)   
  8.     formula="arbitrary SQL expression" (6)   
  9.     access="field|property|ClassName" (7)   
  10.     lazy="true|false" (8)   
  11.     unique="true|false" (9)   
  12.     not-null="true|false" (10)   
  13.     optimistic-lock="true|false" (11)   
  14.     generated="never|insert|always" (12) />  
(1) name: 属性的名字,以小写字母开头
(2) column (可选 - 默认为属性名字): 对应的数据库字段名。也可以通过嵌套的<column>元素指定。
(3) type (可选): 一个Hibernate类型的名字。
typename可以是如下几种:
A:Hibernate基本类型名(比如:integer, string, character,date, timestamp, float, binary, serializable, object, blob)。
B:一个Java类的名字,这个类属于一种默认基础类型 (比如: int, float,char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob)。
C:一个可以序列化的Java类的名字。
D:一个自定义类型的类的名字。(比如:cn.javass.type.MyCustomType)。
如果你没有指定类型,Hibernarte会使用反射来得到这个名字的属性,以此来猜测正确的Hibernate类型。 Hibernate会按照规则B,C,D的顺序对属性读取器(getter方法)的返回类进行解释。然而,这还不够。 在某些情况下你仍然需要type属性。(比如,为了区别Hibernate.DATE 和Hibernate.TIMESTAMP,或者为了指定一个自定义类型。)
(4) update, insert (可选 - 默认为 true) : 表明用于UPDATE 和/或 INSERT 的SQL语句中是否包含这个被映射了的字段。这二者如果都设置为false 则表明这是一个“外源性(derived)”的属性,它的值来源于映射到同一个(或多个) 字段的某些其他属性,或者通过一个trigger(触发器)或其他程序生成。
(5) formula (可选): 一个SQL表达式,定义了这个计算属性的值。计算属性没有和它对应的数据库字段,相当于是一个子查询。
(6) access (可选 – 默认值property): Hibernate访问属性值的策略
access属性用来让你控制Hibernate如何在运行时访问属性。在默认情况下, Hibernate会使用属性的get/set方法对。如果你指明access="field", Hibernate会忽略get/set方法对,直接使用反射来访问成员变量。你也可以指定你自己的策略, 这就需要你自己实现org.hibernate.property.PropertyAccessor接口, 再在access中设置你自定义策略类的名字。
(7) lazy (可选 - 默认为 false): 指定 指定实例变量第一次被访问时,这个属性是否延迟抓取(fetched lazily)( 需要运行时字节码增强)。
(8) unique (可选): 使用DDL为该字段添加唯一的约束。 同样,允许它作为property-ref引用的目标。
(9) not-null (可选): 使用DDL为该字段添加可否为空(nullability)的约束。
(10) optimistic-lock (可选 - 默认为 true): 指定这个属性在做更新时是否需要获得乐观锁定(optimistic lock)。 换句话说,它决定这个属性发生脏数据时版本(version)的值是否增长。
(11) generated (可选 – 默认值never): 表明此属性值是否由数据库生成
 
<component>元素
<component> 元素把子对象的一些元素与父类对应的表的一些字段映射起来。然后组件可以定义它们自己的属性、组件或者集合。

java代码:
  1. <component  
  2. name="propertyName"(1)  
  3. class="className"(2)  
  4. insert="true|false"(3)  
  5. update="true|false"(4)  
  6. access="field|property|ClassName"(5)  
  7. lazy="true|false"(6)  
  8. optimistic-lock="true|false"(7)  
  9. unique="true|false"(8)  
  10. >  
  11. <property ...../>  
  12. <many-to-one .... />  
  13. </component>  
 
(1)name:属性名。
(2)class(可选 — 默认为通过反射得到的属性类型):组件(子)类的名字。
(3)insert:被映射的字段是否出现在 SQL 的 INSERT 语句中?
(4)update:被映射的字段是否出现在 SQL 的 UPDATE 语句中?
(5)access(可选 — 默认为 property):Hibernate 用来访问属性值的策略。
(6)lazy(可选 — 默认是 false):表明此组件应在实例变量第一次被访问的时候延迟加载(需要编译时字节码装置器)。
(7)optimistic-lock(可选 — 默认是 true):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version)。
(8)unique(可选 — 默认是 false):表明组件映射的所有字段上都有唯一性约束。
 
其 <property> 子标签为子类的一些属性与表字段之间建立映射。
组件(Component)是一个被包含的对象,在持久化的过程中,它被当作值类型,
而并非一个实体的引用,指的是对象的合成。使用示例如下:
1:新建一个PersonModel,包含字段:userId和name
2:修改UserModel,在里面去掉userId和name,然后添加一个字段:p,类型为PersonModel,也要对应的getter和setter方法
3:在UserModel.hbm.xml中修改配置如下:
<hibernate-mapping>  
    <class name="cn.javass.h3.hello.UserModel" table="tbl_user">  
        <id name="uuid">  
            <generator class="assigned"/>  
        </id>  
        <component name="p" class="cn.javass.h3.hello.PersonModel">          
            <property name="userId"></property>  
            <property name="name"></property>  
        </component>  
        <property name="age"></property>  
    </class>  
</hibernate-mapping>
 
 
4:相应的修改Client文件如下:

java代码:
  1. //准备数据  
  2. UserModel um = new UserModel();  
  3. um.setUuid("13");  
  4. um.setAge(1);  
  5. PersonModel pm = new PersonModel();  
  6. pm.setUserId("id1");  
  7. pm.setName("name1");  
  8. um.setP(pm);  
 
5:运行测试
<join>元素
使用 <join> 元素,假若在表之间存在一对一关联,可以将一个类的属性映射到多张表中。

java代码:
  1. <join  
  2. table="tablename"(1)  
  3. schema="owner"(2)  
  4. catalog="catalog"(3)  
  5. fetch="join|select"(4)  
  6. inverse="true|false"(5)  
  7. optional="true|false"(6)  
  8. >  
  9. <key ... />  
  10. <property ... />  
  11. </join>  
(1)table:被连接表的名称。
(2)schema(可选):覆盖在根 <hibernate-mapping> 元素中指定的schema名字。
(3)catalog(可选):覆盖在根<hibernate-mapping> 元素中指定的catalog名字。
(4)fetch(可选 — 默认是 join):如果设置为默认值 join,Hibernate 将使用一个内连接来得到这个类或其超类定义的 <join>,而使用一个外连接来得到其子类定义的 <join>。如果设置为 select,则 Hibernate 将为子类定义的 <join> 使用顺序选择。这仅在一行数据表示一个子类的对象的时候才会发生。对这个类和其超类定义的 <join>,依然会使用内连接得到。
(5)inverse(可选 — 默认是 false):如果打开,Hibernate 不会插入或者更新此连接定义的属性。
(6)optional(可选 — 默认是 false):如果打开,Hibernate 只会在此连接定义的属性非空时插入一行数据,并且总是使用一个外连接来得到这些属性。
 
例如,一个人(person)的地址(address)信息可以被映射到单独的表中(并保留所有属性的值类型语义):

java代码:
  1. <class name="Person"  table="PERSON">  
  2.   <id name="id" column="PERSON_ID">...</id>  
  3.   <join table="ADDRESS">  
  4.     <key column="ADDRESS_ID"/>  
  5.     <property name="address"/>  
  6.     <property name="zip"/>  
  7.     <property name="country"/>  
  8.   </join>  
...
此特性常常对遗留数据模型有用
 
<properties>元素
<properties> 元素允许定义一个命名的逻辑分组(grouping)包含一个类中的多个属性。这个元素最重要的用处是允许多个属性的组合作为 property-ref 的目标(target)。这也是定义多字段唯一约束的一种方便途径。
 
基本定义如下:

java代码:
  1. <properties  
  2. name="logicalName"   (1)  
  3. insert="true|false"  (2)  
  4. update="true|false"  (3)  
  5. optimistic-lock="true|false" (4)  
  6. unique="true|false"  (5)  
  7. >  
  8. <property ...../>  
  9. <many-to-one .... />  
  10. </properties>  
 
(1)name:分组的逻辑名称 — 不是实际属性的名称。
(2)insert:被映射的字段是否出现在SQL的INSERT语句中
(3)update:被映射的字段是否出现在SQL的UPDATE语句中
(4)optimistic-lock(可选 — 默认是 true):表明更新此组件是否需要获取乐观锁。换句话说,当这个属性变脏时,是否增加版本号(Version)。
(5)unique(可选—默认 false):表明组件映射的所有字段上都有唯一性约束。
<properties>元素的简单示例
<properties name="name" unique="true" update="false">
   <property name="firstName"/>
   <property name="initial"/>
   <property name="lastName"/>
</properties>
在其他元素里面,就可以使用属性参照来引用了,如property-ref="name"
 
与对象继承相关的配置
鉴别器(discriminator)、子类、连接的子类、联合子类、连接、Any元素
 
与关系相关的配置
多对一(many-to-one)、一对一(one-to-one)、key映射
 
与version类似的timestamp
同样用在乐观锁的配置上,作为版本的替代。时间戳本质上是一种对乐观锁定的一种不是特别安全的实现,并不推荐使用。
自然ID(natural-id)
在<natural-id>元素中列出自然键的属性。Hibernate会帮你生成必须的唯一键值和非空约束,但这一映射不是为了把自然键作为主键而准备的。
 
动态组件(dynamic-component)
类似于Component元素,由Hibernate根据配置进行动态映射Map类型,不推荐。
 
关于CLOB与BLOB的区别(写得不错)
posted @ 2017-07-15 10:26  乐在克里特  阅读(206)  评论(0编辑  收藏  举报