先给出一份常见的持久化类配置文件大概熟悉一下
<hibernate-mapping>
<class name="zyw.app.domain.Person1">
<id name="id" type="java.lang.Integer">
<generator class="identity" />
</id>
<property name="name" type="java.lang.String"/>
<property name="age" type="java.lang.Integer"/>
<list name="schools" inverse="false" table="school" lazy="true">
<key>
<column name="person_id" />
</key>
<list-index column="schools_order"/>
<element type="java.lang.String">
<column name="school_name" />
</element>
</list>
</class>
</hibernate-mapping>
一、映射文件结构
Hibernate的持久化类和关系数据库之间的映射通常是用一个XML文档来定义的。该文档通过一系列XML元素的配置,来将持久化类与数据库表之间建立起一一映射。这意味着映射文档是按照持久化类的定义来创建的,而不是表的定义。
1、根元素:<hibernate-mapping>,每一个hbm.xml文件都有唯一的一个根元素,包含一些可选的属性
1)package:指定一个包前缀,如果在映射文档中没有指定全限定的类名,就使用这个作为包名,如
<hibernate-mapping package="com.demo.hibernate.beans">
<class name="User" ...>
< /hibernate-mapping>
< hibernate-mapping>
<class name="com.demo.hibernate.beans.User" ...>
< /hibernate-mapping>
2)schema:数据库schema的名称
3)catalog:数据库catalog的名称
4)default-cascade:默认的级联风格,默认为none
5)default-access:Hibernate用来访问属性的策略
6)default-lazy:指定了未明确注明lazy属性的Java属性和集合类,Hibernate会采取什么样的默认加载风格,默认为true
7)auto-import:指定我们是否可以在查询语言中使用非全限定的类名,默认为true,如果项目中有两个同名的持久化类,则最好在这两个类的对应的映射文件中配置为false
2、<class>定义类:根元素的子元素,用以定义一个持久化类与数据表的映射关系,如下是该元素包含的一些可选的属性
1)name:持久化类(或者接口)的Java全限定名,如果这个属性不存在,则Hibernate将假定这是一个非POJO的实体映射
2)table:对应数据库表名
3)discriminator-value:默认和类名一样,一个用于区分不同的子类的值,在多态行为时使用
4)mutable:表明该类的实例是可变的或者是不可变的
5)schema:覆盖根元素<hibernate-mapping>中指定的schema名字
6)catalog:覆盖根元素<hibernate-mapping>中指定的catalog名字
7)proxy:指定一个接口,在延迟装载时作为代理使用
8)dynamic-update:指定用于UPDATE的SQL将会在运行时动态生成,并且只更新那些改变过的字段
9)dynamic-insert:指定用于INSERT的SQL将会在执行时动态生成,并且只包含那些非空值字段
10)select-before-update:指定HIbernate除非确定对象真正被修改了(如果该值为true),否则不会执行SQL UPDATE操作。在特定场合(实际上,它只在一个瞬时对象关联到一个新的Session中时执行的update()中生效),这说明Hibernate会在UPDATE之前执行一次额外的SQL SELECT操作,来决定是否应该执行UPDATE
11)polymorphism:多态,界定是隐式还是显式的多态查询
12)where:指定定个附加的SQLWHERE条件,在抓取这个类的对象时会增加这个条件
13)persister:指定一个定制的ClassPersister
14)batch-size:指定一个用于根据标识符(identifier)抓取实例时使用的'batch size'(批次抓取数量)
15)optimistic-lock:乐观锁定,决定乐观锁定的策略
16)lazy:通过设置lazy="false",所有的延迟加载(Lazy fetching)功能将未被激活(disabled)
17)entity-name
18)check:这是一个SQL表达式,用于为自动生成的schema添加多行(multi-row)约束检查
19)rowid
20)subselect
21)abstract:用于在<union-subclass>的继承结构(hierarchies)中标识抽象超类
二、映射主键
通常情况下,hibernate建议为持久化类定义一个标识属性,用于唯一的标识某个持久化实例
标识属性通过<id.../>元素来指定,<id.../>元素中的name属性的值就是持久化类的标识属性名,除此之外还可指定如下几个属性
1)type:标识Hibernate类型的名字
2)column:数据库表的主键这段的名字
3)unsaved-value:用来标志该实例是刚刚创建的,尚未保存。可以用来区分对象的状态
4)access:Hibernate用来访问属性值的策略
尽量避免使用复杂的物理主键,应该为数据库增加一列,作为逻辑主键,hibernate为这种逻辑主键提供了主键生成器,用<generator>元素来指定主键的生成器
该元素的作用是指定主键的生成器,通过一个class属性指定生成器对应的类。(通常与<id>元素结合使用)
<id name="id" column="ID" type="integer">
<generator class="native" />
< /id>
--native是Hibernate主键生成器的实现算法之一,由Hibernate根据底层数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式。
Hibernate提供的内置生成器:
1)assigned算法
2)hilo算法
3)seqhilo算法
4)increment算法
5)identity算法
6)sequence算法
7)native算法
8)uuid.hex算法
9)uuid.string算法
10)foregin算法
11)select算法
三、映射普通属性
普通属性用<property>元素来表示持久化类的属性与数据库表字段之间的映射,包含如下属性:
1)name:持久化类的属性名,以小写字母开头
2)column:数据库表的字段名
3)type:Hibernate映射类型的名字
4)update:表明用于UPDATE的SQL语句中是否包含这个被映射的字段,默认为true
5)insert:表明用于INSERT的SQL语句中是否包含这个被映射是否包含这个被映射的字段,默认为true
6)formula:一个SQL表达式,定义了这个计算属性的值
7)access:Hibernate用来访问属性值的策略
8)lazy:指定实例变量第一次被访问时,这个属性是否延迟抓取,默认为false
9)unique:使用DDL为该字段添加唯一的约束,此外,这也可以用做property-ref的目标属性
10)not-null:使用DDL为该字段添加可否为空的约束
11)optimistic-lock:指定这个属性在进行更新时是否需要获得乐观锁定(换句话说,它决定这个属性发生脏数据时版本version的值是否增长)
access属性用来让你控制Hibernate如何在运行时访问属性。默认情况下,Hibernate会使用属性的get/set方法对。如果你指明access="field",则Hibernate会忽略get/set方法对,直接使用反射来访问成员变量。
formula属性是个特别强大的的特征。用一个SQL表达式生成计算的结果,它会在这个实例转载时翻译成一个SQL查询的SELECT子查询语句。如:
<property name="totalPrice" formula="(SELECT SUM(*) FROM user)" />
如下面的实体类
public class News
{
private Integer id;
private String title;
private String content;
private String fullContent;
//省略属性的getter和setter方法
}
对应的配置文件News.hbm.xml
<?xml version="1.0" encoding="gb2312"?>
<!-- 指定Hiberante3映射文件的DTD信息 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- hibernate-mapping是映射文件的根元素 -->
<hibernate-mapping package="org.crazyit.app.domain">
<!-- 每个class元素对应一个持久化对象 -->
<class name="News" table="news_table">
<!-- id元素定义持久化类的标识属性 -->
<id name="id">
<generator class="identity"/>
</id>
<!-- property元素定义常规属性 -->
<property name="title" not-null="true"/>
<property name="content"/>
<!-- 通过formula指定该属性值没有对应的实际数据列
该属性值将由系统根据表达式来生成-->
<property name="fullContent"
formula="(select concat(nt.title,nt.content)
from news_table nt where nt.id= id)"/>
</class>
</hibernate-mapping>
利用formula的强大特征,可以实现持久化类某个属性的生成,而该属性不会保存,不会有对应的数据列 (即数据库无此列数据,只包含在实体类里)
当保存News对象时
News n = new News();
n.setTitle("xxx");
n.setContent("yyy");
session.save(n);
数据库底层并无fullContent数据列,当再次取出News对象时,hibernate将执行formula配置的sql语句得出fullContent的属性值
News n2 = session.get(News.class,1)
System.out.println(n2.getFullContent)
结果为"xxxyyy"
利用formula可以让hibernate自动生成属性的值,我们也可以由数据库的触发器来生成,不过数据库必须增加fullContent数据列,
只要将
<property name="fullContent"
formula="(select concat(nt.title,nt.content)
from news_table nt where nt.id= id)"/>
改为
<property name="fullContent" generated="insert"/>
hibernate将会让数据库执行insert类型触发器
四、映射集合、组件。。。属性
Hibernate要求持久化集合值字段必须声明为接口,可以是java.util.Set、java.util.Collection、java.util.List、java.util.Map、java.util.SortedSet、java.util.SortedMap等
对于hibernate中,集合属性在Hibernate的映射文件中是非常常见的,也是非常重要的内容,理解和熟练掌握常用的集合属性则显得更为重要。在hibernate的配置文件中,例如每个人的考试成绩,就是典型的Map结构,每门功课对应一门成绩。或者更简单的集合属性,某个企业的部门,一个企业通常对应多个部门等。集合属性是现实生活中非常普遍的属性关系。集合属性大致有两种:第一种是单纯的集合属性,例如像List,Set或数组等集合属性;还有一种就是Map结构的集合属性。每个属性都有对应的key映射.基本配置如下
<hibernate-mapping>
<class name="zyw.app.domain.Person1">
<id name="id" type="java.lang.Integer">
<generator class="identity" />
</id>
<property name="name" type="java.lang.String"/>
<property name="age" type="java.lang.Integer"/>
<list name="schools" inverse="false" table="school" lazy="true">
<key>
<column name="person_id" />
</key>
<list-index column="schools_order"/>
<element type="java.lang.String">
<column name="school_name" />
</element>
</list>
</class>
</hibernate-mapping>
添加集合属性元素配置步骤如下:
1、集合属性的元素大致有如下几种: (1)<set../>元素:可以映射类型为java.util.Set接口的属性,它的元素存放没有顺序且不允许重复,也可以映射类型为java.util.SortSet接口的属性,它的元素可以按自然属性排序,也可以用sort属性指定排序规则
(2)<list.../>元素:可以映射类型为java.util.List接口的属性,它需要在结合属性对象的数据库表中用一个额外的索引列保存每一个元素的位置,即是有属性可重复的。
(3)<bag.../>元素:可以映射java.util.Collection接口的属性,它的元素可能重复,但不保存属性,和set差不多,正因为有它,是因为如果通常使用list比较多,并且不想让添加一列的话,就用它。
(4)<map.../>元素:可以映射为java.util.Map接口的属性,它的元素以键值对的形式保存,也是无序的,也可以映射类型为java.util.SortMap接口的属性,它的元素可以按自然顺序排序,也可以用sort属性指定排序规则
(5)<array.../>元素:可以映射类型为数组的属性,但在实际运用中用的极少
(6)<primitive-array.../>元素:可以映射类型为基本数据类型数组的属性,但在实际运用中用的极少
2、因为集合属性都需要保存到另一个数据表中,所以保存集合属性的数据表必须包含一个外键列用于参照到主键列,可以在集合属性元素中用子元素<key.../>来映射
<key.../>元素有如下属性
column:指定外键字段的列名
on-delete:是否打开级联删除
property-ref:指定外键字段是否为原表的主键
not-null:非空约束
update:是否可更新
unique:是否唯一约束
2、除了<set.../>和<bag.../>元素外,都要为集合元素的数据表指定一个索引列——用于保存数组索引,List索引,或者Map集合的key索引,在集合属性元素中用于映射索引列的子元素有如下几个
<List-index/>用于List,数组
<map-key/>用于映射Map,基本数据类型的索引列
<map-key-many-to-many/>用于Map中实体类型的引用(即key为实体类)
<composite-map-key/>用于Map中复合类型的引用(即key为组件,非实体类,就是一个复合类型类)
3、最后,我们还需要映射集合元素的值属性
<element.../>集合元素是基本类型或包装类,字符串类型,日期类型
<composite-element.../>集合元素是复合类型的引用(即key为组件,非实体类,就是一个复合类型类)
<one-to-many.../>或<many-to-many.../>集合元素是实体类型的引用(即key为实体类)
记忆规则其实很简单,可以这么记:基本配置:
<hibernate-mapping>
<class name="zyw.app.domain.Person1">
<id name="id">
<generator class="identity" />
</id>
<property name="name"/>
<property name="age"/>
</class>
</hibernate-mapping>
A.如果<property/>属性为集合属性,按照123步骤置换成对应的元素即可,如schools为一个list属性
<list name="schools" inverse="false" table="school" lazy="true">
<key>
<column name="person_id" />
</key>
<list-index column="schools_order"/>
<element type="java.lang.String">
<column name="school_name" />
</element>
</list>
B.如果
<property/>属性为组件属性,如Name类(Name是一个自定义类,含有first和last两个属性),置换成<component.../>元素,要指定自定义类的路径
<component name="name" class="zyw.app.componet.Name">
<property name="first" column="FIRST"></property>
<property name="last" column="LAST"></property>
</component>
同理
如果组件属性里还有集合属性,继续A置换
如果组件属性里还有组件属性,继续B置换,<component.../>变成<nested-composite-element.../>
如果集合Map的索引属性为组件属性,继续B置换,<component.../>变成<nested-composite-element.../>,子元素为<key-property.../>或<key-many-to-one.../>
C。如果<id.../>为组件属性,组件类必须重写过equals和hashCode方法,<id.../>元素置换为
<composite-id name="xxx" class="xxx.xxx.xxx">
<key-property name="xxx"/>
<key-property name="xxx"/>
</composite-id>
或者多列为联合主键,省去name和class属性即可,效果一样
<composite-id>
<key-property name="xxx"/>
<key-property name="xxx"/>
</composite-id>
五、JPAAnnotation标注实体
<preclass="java"name="code">@Entity
@Table(name="person_table")
public class Person
{
/* 指定使用复合主键类是Name */
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name="first"
, column=@Column(name="person_first")),
@AttributeOverride(name="last"
, column=@Column(name="person_last" , length=20))
})
private Name name;
//普通属性
@Column(name="person_email")
private String email;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="name"
, column=@Column(name="cat_name" , length=35)),
@AttributeOverride(name="color"
, column=@Column(name="cat_color"))
})
//组件属性,代表此人拥有的宠物
private Cat pet;
//name属性的setter和getter方法
public void setName(Name name)
{
this.name = name;
}
public Name getName()
{
return this.name;
}
//email属性的setter和getter方法
public void setEmail(String email)
{
this.email = email;
}
public String getEmail()
{
return this.email;
}
//pet属性的setter和getter方法
public void setPet(Cat pet)
{
this.pet = pet;
}
public Cat getPet()
{
return this.pet;
}
}</pre><br>
<br>
<pre></pre>
<preclass="html"name="code"></pre>
<br>