Hibernate的基本配置文件有两种:hibernate.cfg.xml和.hbm.xml文件。前者包含了Hibernate与数据库的基本连接信息,在Hibernate工作的初始阶段,这些信息被先后加载到Configuration和SessionFactory实例;后者包含了Hibernate的基本映射信息,即系统中每一个类与其对应的数据库表之间的关联信息,在Hibernate工作的初始阶段,这些信息通过hibernate.cfg.xml的mapping节点被加载到Configuration和SessionFactory实例。这两种文件信息包含了Hibernate的所有运行期参数。下面我们用详细的例子来说明这两种文件的基本结构和内容。
一、hibernate.cfg.xml文件:
<!--该文件的开头信息,对Hibernate而言,该类文件基本都这么开头:)-->
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- 正文开始 -->
<hibernate-configuration>
<!--下面是数据库的基本连接信息,对一个应用来说,设置一个session-factory节点就够了,除非我们中间使用了多个数据库-->
<session-factory>
<!--用户名 -->
<property name="connection.username">root</property>
<!--url信息 -->
<property name="connection.url">jdbc:mysql://localhost:3306/webases</property>
<!--数据库方言信息-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--密码 -->
<property name="connection.password">274507</property>
<!--数据库驱动信息 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!--指定Hibernate映射文件路径 -->
<mapping resource="com/Hibernate/test_products.hbm.xml" />
</session-factory>
</hibernate-configuration>
二、.hbm.xml文件:
由于Hibernate的关联关系包含了一对一、一对多、多对一和多对多等四种类型,因此,也就有分别与之对应的四种.hbm.xml文件。下面我们就以比较常用的双向“一对多”型关联关系为例,介绍一下.hbm.xml文件的基本结构和内容。有关Hibernate更详细的内容,请参考相关文资料。
该例中有两张数据库表:一张为“省”表,另一张为“市”表,所用的数据库为MySQL。二者的建表语句如下:
CREATE TABLE IF NOT EXISTS Province
(
Guid INT NOT NULL AUTO_INCREMENT,
Provincename VARCHAR(16) NOT NULL,
PRIMARY KEY (Guid)
) TYPE=InnoDB;
CREATE TABLE IF NOT EXISTS City
(
Guid INT NOT NULL AUTO_INCREMENT,
Cityname VARCHAR(32) NOT NULL,
ProvinceID INT NOT NULL,
PRIMARY KEY (Guid)
) TYPE=InnoDB;
ALTER TABLE City ADD CONSTRAINT CityRFProvince FOREIGN KEY (ProvinceID)
REFERENCES Province (Guid) ON DELETE CASCADE ON UPDATE RESTRICT;
Province表为主控方,City表为被控方,两者之间存在双向的一对多的关系。表City通过外键ProvinceID与表Province进行关联:当表Province中有记录被删除时,表City中相关记录亦被删除;当表Province中有记录被保存或者更新时,表City中相关记录无任何变化。
将Hibernate自带工具Middlegen生成的Province.hbm.xml文件进行修改,内容如下:
<!--该文件的开头信息,对Hibernate而言,该类文件基本都这么开头:)-->
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"
>
<!-- 映射文件开始 -->
<hibernate-mapping>
<!-- 下面的class节点定义了Province类和对应数据库表之间的关联关系 -->
<class
name="com.xxx.hibernate.Province"
table="Province"
>
<!-- 下面的两个节点定义了Province类中的属性和该类对应数据库表中的字段之间的关联关系,其中Guid为对应数据库表的主键 -->
<id
name="guid"
type="int"
column="Guid"
>
<generator class="native" />
</id>
<property
name="provincename"
type="java.lang.String"
column="Provincename"
not-null="true"
length="16"
>
</property>
<!-- 下面的set节点定义了Province类和City类之间的”一对多“型关联关系 -->
<set
name="cities"<!-- 集合属性的名称 -->
lazy="true"<!-- 是否允许延迟加载 -->
inverse="true"<!-- 定义这个集合是否为双向关联关系中的方向一端 -->
cascade="delete"<!-- 定义有关操作是否关联到子实体(此处指City类对象) -->
>
<key>
<column name="ProvinceID" /><!-- 定义集合所对应的数据库表的外键 -->
</key>
<one-to-many
class="com.xxx.hibernate.City"<!-- 定义集合所属的类-->
/>
</set>
</class>
</hibernate-mapping>
将Hibernate自带工具Middlegen生成的City.hbm.xml文件进行修改,内容如下:
<!--该文件的开头信息,对Hibernate而言,该类文件基本都这么开头:)-->
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"
>
<!-- 映射文件开始 -->
<hibernate-mapping>
<!-- 下面的class节点定义了City类和对应数据库表之间的关联关系 -->
<class
name="com.xxx.hibernate.City"
table="City"
>
<!-- 下面的两个节点定义了City类中的属性和该类对应数据库表中的字段之间的关联关系,其中Guid为对应数据库表的主键-->
<id
name="guid"
type="int"
column="Guid"
>
<generator class="native" />
</id>
<property
name="cityname"
type="java.lang.String"
column="Cityname"
not-null="true"
length="32"
>
</property>
<!-- 下面的many-to-one节点定义了Province类和City类之间的”一对多“型关联关系 -->
<many-to-one
name="province"<!-- 属性名称 -->
class="com.xxx.hibernate.Province"<!-- 属性所属的类 -->
cascade="none"<!-- 指定哪些操作会从父对象(此处指City类对象)级联到子对象(此处指Province类对象) -->
outer-join="auto"<!-- 设置父子对象之间是否存在外连接 -->
not-null="true"<!-- 指定该属性是否一定为非空 -->
>
<column name="ProvinceID" /><!-- 定义父对象(此处指City类对象)所对应的数据库表的外键 -->
</many-to-one>
</class>
</hibernate-mapping>
多对多的双向关联关系(中间表)
2007-06-06 17:26
在多对多的关联关系中,可拆分为两个一对多的关联关系,即在两个表中间增加一个关联表,记录这两个表之间的关联关系。若抛开关联表,则原2个表之间看不出任何的关系。
以为考试类别和考试科目为例,详细讲解在添加关联表的情况下两个表之间的hibernate设置。
考试类别表:exam_sort_enum
id:integer
name:string
考试科目表:subject
id:integer
name:string
考试类别科目关联表
exam_sort_enum_id:integer 对应考试类别表的id
subject_id:integer 对应考试科目表的id
ExamSortEnum.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class
name="model.ExamSortEnum"
table="EXAM_SORT_ENUM"
lazy="false"
>
<id
name="id"
type="integer"
column="ID"
length="22"
>
<generator class="increment" />
</id>
<property
name="name"
type="string"
column="NAME"
length="255"
/>
<set name="subject" table="EXAM_SORT_ENUM_SUBJECT" lazy="true" cascade="save-update">
<key column="exam_sort_enum_id"/>
<many-to-many column="subject_id" class="model.Subject"/>
</set>
</class>
</hibernate-mapping>
ExamSortEnum.java
package model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class ExamSortEnum implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set subject = new HashSet();
public ExamSortEnum(){}
public ExamSortEnum(Integer id){
setId(id);
}
public void setSubject(Set subject){
this.subject = subject;
}
public Set getSubject(){
return this.subject;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
关于映射文件:
映射文件要设置set,
name=subject 为ExamSortEnum.java文件中定义的Set对象,存储多个Subject类型的容器。
table="EXAM_SORT_ENUM_SUBJECT" 为对应的中间表的表名,由于两个业务表之间不能直接打交道,只能通过中间表来进行关联。
lazy="true" 延迟加载
cascade="save-update" 级联保存更新,若设置为all,delete,all-delete-orphans,则在删除一个ExamSortEnum对象时,关联的Subject对象也被删除,而此关联的subject对象可能被其他的为ExamSortEnum对象所引用。
<key column="exam_sort_enum_id"/> 指定中间表中参照为Exam_Sort_Enum表的外键为exam_sort_enum_id
<many-to-many>
column="subject_id" Exam_Sort_Enum表参照Subject表的外键为subject_id,即Exam_Sort_Enum表通过subject_id与Subject表关联
class="model.Subject" 指定set中name=subject中存放的是model.Subject对象。
Subject.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class
name="model.Subject"
table="SUBJECT"
lazy="false"
>
<id
name="id"
type="integer"
column="ID"
length="22"
>
<generator class="increment" />
</id>
<property
name="name"
type="string"
column="NAME"
length="200"
/>
<set name="examSortEnum" table="EXAM_SORT_ENUM_SUBJECT" lazy="true" inverse="true" cascade="save-update">
<key column="subject_id"/>
<many-to-many column="exam_sort_enum_id" class="model.ExamSortEnum"/>
</set>
</class>
</hibernate-mapping>
Subject.java
package model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Subject implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set examSortEnum = new HashSet();
public Subject(){}
public Subject(Integer id){
setId(id);
}
public void setExamSortEnum(Set examSortEnum){
this.examSortEnum = examSortEnum;
}
public Set getExamSortEnum(){
return this.examSortEnum;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
关于映射文件:
内容与ExamSortEnum.hbm.xml差不多,只是多了一个inverse="true",告诉hibernate控制权不在此处,两个映射文件只能设置一个。
测试类:
package model;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class ExamSortEnumTest {
public static SessionFactory sf ;
static{
try{
Configuration cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}catch(Exception e){
e.printStackTrace();
}
}
public void insert1(){
Session sess = sf.openSession();
Transaction tx = sess.beginTransaction();
Subject sa = new Subject();
sa.setName("A1");
Subject sb = new Subject();
sb.setName("B1");
Subject sc = new Subject();
sc.setName("C1");
ExamSortEnum esea = new ExamSortEnum();
esea.setName("A");
esea.getSubject().add(sa);
esea.getSubject().add(sc);
ExamSortEnum eseb = new ExamSortEnum();
eseb.setName("B");
eseb.getSubject().add(sb);
eseb.getSubject().add(sc);
sess.save(esea);
sess.save(eseb);
tx.commit();
sess.close();
}
public static void main(String[] args){
ExamSortEnumTest et = new ExamSortEnumTest();
et.insert1();
}
}
执行后的结果:
考试类别表:exam_sort_enum
id name
3 A
4 B
考试科目表:subject
id name
3 C1
4 A1
5 B1
考试类别科目关联表
exam_sort_enum_id subject_id
3 3
3 4
4 3
4 5
Hibernate配置文件参数说明
HIbernate的参数使用说明
set节点有以下属性(摘自Hibernate文档):
(1) name 集合属性的名称
(2) table (可选??默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用)
(3) schema (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema
(4) lazy (可选??默认为false) lazy(可选--默认为false) 允许延迟加载(lazy initialization )(不能在数组中使用)
(5) inverse (可选??默认为false) 标记这个集合作为双向关联关系中的方向一端。
(6) cascade (可选??默认为none) 让操作级联到子实体
(7) sort(可选)指定集合的排序顺序, 其可以为自然的(natural)或者给定一个用来比较的类。
(8) order-by (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序
(9) where (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用)
(10) outer-join(可选)指定这个集合,只要可能,应该通过外连接(outer join)取得。在每一个SQL语句中, 只能有一个集合可以被通过外连接抓取(译者注: 这里提到的SQL语句是取得集合所属类的数据的Select语句)
(11) batch-size (可选, 默认为1) 指定通过延迟加载取得集合实例的批处理块大小("batch size")。
(12) access(可选-默认为属性property):Hibernate取得属性值时使用的策略
many-to-one节点有以下属性(摘自Hibernate文档):
(1) name: 属性名。
(2) column (可选): 字段名。
(3) class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。
(4) cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。
(5) outer-join(外连接) (可选 - 默认为 自动): 当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。
(6) update, insert (可选 - defaults to true) 指定对应的字段是否在用于UPDATE 和/或 INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序。
(7) property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。
(8) access (可选 - 默认是 property): Hibernate用来访问属性的策略。
cascade 属性允许下列值: all, save-update, delete, none。设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“Lifecycle Objects(自动管理生命周期的对象)”。
outer-join参数允许下列三个不同值:
auto (默认) 使用外连接抓取关联(对象),如果被关联的对象没有代理(proxy)
true 一直使用外连接来抓取关联
false 永远不使用外连接来抓取关联
Struts2提供了对不同种类返回结果的支持,常见的有JSP,FreeMarker,Velocity等。
Struts2支持的不同类型的返回结果为:
名字 说明
chain 用来处理Action链
dispatcher 用来转向页面,通常处理JSP,这是默认的结果类型
freeMarker 处理FreeMarker模板
httpHeader 用来控制特殊的Http行为
redirect 重定向到一个URL
redirect-action 重定向到一个Action
stream 向浏览器发送InputSream对象,通常用来处理文件下载
velocity 处理Velocity模板
xslt 处理XML/XLST模板
plaintext 显示原始文件内容,例如文件源代码
tiles 结合Tile使用
另外第三方的Result类型还包括JasperReports Plugin,专门用来处理JasperReport类型的报表输出;Jfreechart Plugin;JSF Plugin
动态返回结果
有些时候,只有当Action执行完毕的时候我们才知道要返回哪个结果,这个时候我们可以在Action内部定义一个属性,这个属性用来存储Action执行完毕之后的result值,例如:
private String nextAction;
public String getNextAction() {
return nextAction;
}
在strutx.xml配置文件中,我们可以使用来引用到Action中的属性,通过表示的内容来动态的返回结果,例如:
<action name="fragment" class="FragmentAction">
<result name="next" type="redirect-action"></result>
</action>
上述Action的execute方法返回next的时候,还需要根据nextAction的属性来判断具体定位到哪个Action。