Hibernate对象关系映射,基本工作原理是将对象数据保存到关系数据库的表中,以及将关系数据库中数据读入到对象中。
对象关系映射Object Relation Mapping, ORM,数据持久化
Hibernate 工作过程
搭建Hibernate实验环境 需要引入Hibernate下的核心包hibernate3.jar 、依赖包即 \lib 文件夹下的所有jar文件 、mysql驱动包 、Hibernate核心配置文件 hibernate.cfg.xml。
驱动包jar包,如下所示:
antlr-2.7.6.jar
commons-collections-3.1.jar
dom4j-1.6.1.jar
hibernate3.jar
javassist-3.4.GA.jar
jta-1.1.jar
slf4j-api-1.5.2.jar
log4j-1.2.15.jar
slf4j-log4j12-1.5.2.jar
mysql-connector-java-5.1.6-bin.jar
ddl.sql(自定义的mysql语句,在首先Hibernate执行之前,需要先用mysql命令行执行这一个文件)
hibernate.cfg.xml文件配置如下:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库方言设置 -->
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<!-- 数据库连接参数设置 -->
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">jdbc:mysql:///hb_01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--实际操作数据库时是否显示SQL -->
<!--
<property name="hibernate.show_sql">true</property>
-->
<property name="hibernate.format_sql">true</property>
<!--将数据库schema的DDL导出到数据库 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 以下定义实体类与数据库表的映像文件 -->
<mapping resource="com/qiujy/domain/Account.hbm.xml" />
</session-factory>
</hibernate-configuration>
之后,对一个真正的类Accout进行定义,定义如下:
/**
* Filename: Account.java
* Author: qiujy
* Createtime: 2009-1-11
* Copyrights 2009 qiujy All rights reserved.
* EMail: qjyong@gmail.com
*/
package com.qiujy.domain;
import java.util.Date;
public class Account {
private Long id; //对象标示符(OID)
private String loginname;
private String password;
private String email;
private Date registrationTime;
public Account(){}
//省略了getters和setters方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getRegistrationTime() {
return registrationTime;
}
public void setRegistrationTime(Date registrationTime) {
this.registrationTime = registrationTime;
}
}
之后,映射持久化类到数据库表中。
Account.hbm.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Hibernate对象关系映射文件的根元素 -->
<hibernate-mapping>
<!-- class元素用来定义一个持久化类及对应的数据库表 -->
<class name="com.qiujy.domain.Account" table="account">
<!--
id元素:指定每个持久化类的唯一标识(即对象标识符OID)到数据库表主键字段的映射
name属性:指定持久化类的OID名
column属性:指定数据库表主键字段名。此属性的名和映射到数据库表的字段名相同时,可省略
type属性:指定主键映射时所使用的Hibernate类型名。此属性的类型为基本数据类型和String类型时,可省略
-->
<id name="id" column="id" type="long">
<!-- generator元素:指定对象标识符的生成器名。
native生成器把对象标识符值的生成工作交由底层数据库来完成
-->
<generator class="native" />
</id>
<!--
property元素:指定持久化类的每一个要映射到数据库表的字段的属性的信息。
name属性;指定持久化类中要映射到数据库表字段的属性名。
column属性:指定对应的表的字段名。此属性的名和映射到数据库表的字段名相同时,可省略
type属性:指定属性映射所使用的Hibernate类型名。此属性的类型为基本数据类型和String类型时,可省略
not-null属性:指定此属性映射到数据库表的字段值是否允许为值
-->
<property name="loginname" column="loginname" type="string" not-null="true"/>
<property name="password" column="password" type="string" not-null="true"/>
<property name="email" column="email" type="string"/>
<!-- 属性类型为Date类型的必须要明确指定使用的Hibernate类型名 -->
<property name="registrationTime" column="registration_time" type="timestamp"/>
</class>
</hibernate-mapping>
之后就用一个测试用例,利用Hibernate API进行持久化操作了!!!
/**
* Filename: CreateAccountTest.java
* Author: qiujy
* Createtime: 2009-1-11
* Copyrights 2009 qiujy All rights reserved.
* EMail: qjyong@gmail.com
*/
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.qiujy.domain.Account;
/**
* 新增账号的测试
* @author qiujy
*/
public class CreateAccountTest {
public static void main(String[] args) {
//根据hibernate的默认配置文件构建一个SessoinFactory实例
SessionFactory sessionFactory =
new Configuration().configure().buildSessionFactory();
//获取Session实例
Session session = sessionFactory.openSession();
//开启事务
session.beginTransaction();
//创建一个账号
Account acc = new Account();
acc.setLoginname("张三");
acc.setPassword("1234");
acc.setEmail("zs@test.com");
acc.setRegistrationTime(new Date());
//利用Session实例进行持久化操作
session.save(acc);
//提交事务
session.getTransaction().commit();
//关闭Session
session.close();
}
}
下面是Hibernate 工作的过程
掌握持久化类的实例的状态及状态之间的转变,Session的使用与之有关
Hibernate 高级映射
01 集合映射
分别对set,list,bag 和map进行介绍
set
学生有很多爱好,hobbies ( type = “string” ), 可以在Student.hbm.xml中进行如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qiujy.domain.Student" table="student">
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<property name="name" not-null="true" />
<!--
set元素用来映射java.util.Set类型的属性
name属性:指定要映射的属性名
table属性:指定对应的数据库表名
-->
<set name="hobbies" table="student_hobby">
<!-- key子元素:指定集合属性对应的表的外键列 -->
<key column="student_id" />
<!-- element子元素:映射集合内的元素 -->
<element type="string" column="hobby_name" not-null="true" />
</set>
</class>
</hibernate-mapping>
同理,list
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qiujy.domain.Student" table="student">
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<property name="name" not-null="true"/>
<!--
list元素用来映射java.util.List类型的属性
name属性:指定要映射的属性名
table属性:指定对应的数据库表名
-->
<list name="hobbies" table="student_hobby">
<!-- key元素:指定集合属性对应的表的外键列 -->
<key column="student_id" />
<!-- list-index元素:指定索引列 -->
<list-index column="posistion"/>
<!-- element元素:映射集合内的元素 -->
<element type="string" column="hobby_name" not-null="true"/>
</list>
</class>
</hibernate-mapping>
bag( 允许重复元素的无序集合,可以使用java.Util.Collection 或者java.util.List接口 来表示这种语义)
如student中有一个Collection<String> hobbies
字段。
对应的hbm.xml如下:
<bag name="hobbies" table="student_hobby">
<!-- key元素:指定集合属性对应的表的外键列 -->
<key column="student_id" />
<!-- element元素:映射集合内的元素 -->
<element type="string" column="hobby_name" not-null="true"/>
</bag>
映射map
private Map<Long,String> hobbies; //个人爱好
<map name="hobbies" table="student_hobby">
<!-- key元素:指定集合属性对应的表的外键列 -->
<key column="student_id" />
<!-- map-key元素:指定Map属性的键在对应表中的列 -->
<map-key column="hobby_id" type="long"/>
<!-- element元素:映射集合内的元素 -->
<element type="string" column="hobby_name" not-null="true"/>
</map>
排序集合与有序集合太多东西,具体可以看代码。
02 组件映射
1 组件类座位持久化类的单个属性
举个例子,在设计一个购物系统时,客户Customer需要有联系地址,还需要有送货地址,可以Customer中,有homeAddress类和deliverAddress类。
同时,数据库那么在对应的数据库中只设计单一Customer表。
映射关系可以写成如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qiujy.domain.Customer" table="customer">
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<property name="loginname" not-null="true"/>
<property name="password" not-null="true"/>
<property name="email"/>
<!-- 用component元素映射组件类属性homeAddress -->
<component name="homeAddress" class="com.qiujy.domain.Address">
<!-- 用property映射组件类的每个属性 -->
<property name="province" column="home_province"/>
<property name="city" column="home_city"/>
<property name="detail" column="home_detail"/>
<property name="zipcode" column="home_zipcode"/>
<property name="telephone" column="home_telephone"/>
<property name="mobilephone" column="home_mobilephone"/>
</component>
<!-- 用component元素映射组件类属性deliverAddress -->
<component name="deliverAddress" class="com.qiujy.domain.Address">
<property name="province" column="deliver_province"/>
<property name="city" column="deliver_city"/>
<property name="detail" column="deliver_detail"/>
<property name="zipcode" column="deliver_zipcode"/>
<property name="telephone" column="deliver_telephone"/>
<property name="mobilephone" column="deliver_mobilephone"/>
</component>
</class>
</hibernate-mapping>
第二种,组件类作为持久化类的集合属性
例如,一个相册里有很多照片,Album, Photo,持久化类和组件类的区别是,前者有对象标示符,后者没有。
映射文件可以为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 映射持久化类 -->
<class name="com.qiujy.domain.Album" table="album">
<!-- 映射对象标识符 -->
<id name="id" column="id" type="long">
<!-- 指定对象标识符生成器 -->
<generator class="native" />
</id>
<!-- 用property映射每个普通属性 -->
<property name="title"/>
<property name="description"/>
<property name="creationTime" column="creation_time"/>
<!-- 用bag来映射List集合属性 -->
<bag name="photos" table="photo">
<!-- key元素:指定集合属性对应的表的外键列 -->
<key column="album_id" not-null="true" />
<!-- composite-element元素:映射集合里的元素
class属性:指定集合里的元素的类类型
-->
<composite-element class="com.qiujy.domain.Photo">
<!-- 用property映射每个普通属性 -->
<property name="name" />
<property name="filePath" column="file_path" />
<property name="description" />
<property name="width" />
<property name="height" />
</composite-element>
</bag>
</class>
</hibernate-mapping>
详情见: hb_03_component.
3 组件类作为持久化对象的对象标识符属性
比如User这张表,把first_name和last_name 两个字段作为联合主键,要映射到持久化类的话,必须把这两个字段定义到一个组件类:UserOid,用来表示复合对象标识符。
同时,这个组件类,必须实现Serializable接口和重写hashcode()和equals()方法。
详情见: hb_03_componentOid.
03关联关系映射
1. 单向多对一
多对一:多个员工属于同一部门。Department类与Employee类
可以见hb_04_many2one_unidirectional.
2. 单向一对一
每一个中国公民,都有一张身份证,单向的意思是:只考虑从公民这一端找到它的身份证,而身份证这一端不知道公民的存在。
有两种方式。。。
一 基于唯一外键
公民把身份证的主键作为外键,并且这个外键是唯一的。
在citizen.hbm.xml中,配置如下:
<hibernate-mapping>
<!-- 映射持久化类 -->
<class name="com.qiujy.domain.Citizen" table="citizen">
<!-- 映射对象标识符 -->
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<!-- 映射普通属性 -->
<property name="name"/>
<property name="gender"/>
<!-- 用many-to-one元素映射基于唯一外键的一对一关联
name属性:指定关联的属性名
column属性:指定此关联属性在数据库表中的外键字段名
unique属性:指定值为“true”来限制多端的多重性为一
cascade属性:用来指定两个对象之间的操作联动关系
-->
<many-to-one name="idCard"
column="idcard_id"
unique="true"
cascade="all"/>
</class>
</hibernate-mapping>
详情可见:hb_04_one2one_unidirectional_fk
二:基于主键
公民的id就是idcard的id,这种方式叫做基于主键的单向一对一。
citizen.hb.xml
<hibernate-mapping>
<!-- 映射持久化类 -->
<class name="com.qiujy.domain.Citizen" table="citizen">
<!-- 映射对象标识符 -->
<id name="id" column="id">
<!-- foreign表示使用另外一个相关联的对象(用property属性指定的那个属性)的标识符 -->
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<!-- 映射普通属性 -->
<property name="name"/>
<property name="gender"/>
<!-- 用one-to-one元素映射基于主键的一对一关联
name属性:指定关联的属性名
constrained属性:true表示该类对应的数据库表和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
-->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
详情可见:hb_04_one2one_unidirectional_pk
- 双向一对一
也有两种实现方式,基于唯一外键和基于主键的方式。
基于唯一外键的一对一双向关联,其外键可以存放在任意一端,在需要存放外键的一端,使用Many-to-one元素来映射关联对象,同时添加unique=true属性; 没有存放外键的那一端需要使用one-to-one元素,此时还需要通过property-ref属性来指定这一端只是关联另外一端的属性的反向引用,并不需要额外的列或者外键约束,由Hibernate管理这个关系。
例子:hb_04_one2one_bidirecrtional_fk.
基于主键的双向一对一
hb_04_one2one_bidirecrtional_pk.
- 单向一对多
一个账号可以有多个订单(set<Order>
),但是订单上没有写是哪个账号信息
hb_04_many2one_unidirecrtional
5.多向一对多(多向多对一)
一个账号可以有多个订单(set<Order>
),订单上有写是哪个账号信息account_id
hb_04_one2many_bidirecrtional
单向多对多
大学学生和课程之间的关联就是单向多对多关联。 课程不知道有哪些学生选了。
在关系模型中,是无法直接表达两个表之间的多对多关联的,需要有一个中间连接表。在连接表中用外键关联到两个表中。
hb_04_many2many_unidirecrtional双向多对多
大学学生和课程之间的关联就是单向多对多关联。 课程知道有哪些学生选了。
同样,需要一个中间表。
hb_04_many2many_bidirecrtional
04 继承关系映射
1:整体继承层次一张表
singer 父类有两个子类:SingleSinger, Bands. 全部放在一张表,需要一个鉴别字段,判断是SingleSinger还是Bands.
2:每个子类一个表
父类也有表,子类也有表,子类的字段都是独有的字段。
3:每一个具体类一个表。
上面父类的通用字段每一个表中都有。父类没有表。
hb_05_inheritancemapping_1
hb_05_inheritancemapping_2
hb_05_inheritancemapping_3
源代码地址如下:
01-03
http://download.csdn.net/detail/chengyangyy/9119523
04
http://download.csdn.net/detail/chengyangyy/9119537
05
http://download.csdn.net/detail/chengyangyy/9119545