我的例子是一个全国省和市的数据表,省为一个表,市为一个表,所使用的数据库是MySQL 4.1.11。表的结构如下:
2 (
3 Guid INT NOT NULL AUTO_INCREMENT,
4 Provincename VARCHAR ( 16 ) NOT NULL ,
5 PRIMARY KEY (Guid)
6 ) TYPE = InnoDB;
7
8 CREATE TABLE IF NOT EXISTS City
9 (
10 Guid INT NOT NULL AUTO_INCREMENT,
11 Cityname VARCHAR ( 32 ) NOT NULL ,
12 ProvinceID INT NOT NULL ,
13 PRIMARY KEY (Guid)
14 ) TYPE = InnoDB;
15
16 ALTER TABLE City ADD CONSTRAINT CityRFProvince FOREIGN KEY (ProvinceID)
17 REFERENCES Province (Guid) ON DELETE CASCADE ON UPDATE RESTRICT ;
Province表做为主控方,City表做为被控方,两者之间是双向的一对多关系。用Middlegen生成的Province.hbm.xml文件,修改后的内容如下:
2 <! DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
5
6 < hibernate-mapping >
7 <!--
8 Created by the Middlegen Hibernate plugin 2.1
9
10 http://boss.bekk.no/boss/middlegen/
11 http://www.hibernate.org/
12 -->
13
14 < class
15 name ="com.xxx.hibernate.Province"
16 table ="Province"
17 >
18 < meta attribute ="class-description" inherit ="false" >
19 @hibernate.class
20 table="Province"
21 </ meta >
22
23 < id
24 name ="guid"
25 type ="int"
26 column ="Guid"
27 >
28 < meta attribute ="field-description" >
29 @hibernate.id
30 generator-class="native"
31 type="int"
32 column="Guid"
33
34
35 </ meta >
36 < generator class ="native" />
37 </ id >
38
39 < property
40 name ="provincename"
41 type ="java.lang.String"
42 column ="Provincename"
43 not-null ="true"
44 length ="16"
45 >
46 < meta attribute ="field-description" >
47 @hibernate.property
48 column="Provincename"
49 length="16"
50 not-null="true"
51 </ meta >
52 </ property >
53
54 <!-- Associations -->
55
56 <!-- bi-directional one-to-many association to City -->
57 < set
58 name ="cities"
59 lazy ="true"
60 inverse ="true"
61 cascade ="save-update"
62 >
63 < meta attribute ="field-description" >
64 @hibernate.set
65 lazy="true"
66 inverse="true"
67 cascade="save-update"
68
69 @hibernate.collection-key
70 column="ProvinceID"
71
72 @hibernate.collection-one-to-many
73 class="com.xxx.hibernate.City"
74 </ meta >
75 < key >
76 < column name ="ProvinceID" />
77 </ key >
78 < one-to-many
79 class ="com.xxx.hibernate.City"
80 />
81 </ set >
82
83 </ class >
84 </ hibernate-mapping >
85
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取得属性值时使用的策略 |
由于在建立外键的时候就声明了ON DELETE CASCADE,所以在xml的配置文件中cascade声明为save-update。如果声明为all,那么在删除Province表的数据时,会无谓的多出一条删除City的delete语句出来,这将会影响程序的性能。
City.hbm.xml的内容如下:
2 <! DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
5
6 < hibernate-mapping >
7 <!--
8 Created by the Middlegen Hibernate plugin 2.1
9
10 http://boss.bekk.no/boss/middlegen/
11 http://www.hibernate.org/
12 -->
13
14 < class
15 name ="com.xxx.hibernate.City"
16 table ="City"
17 >
18 < meta attribute ="class-description" inherit ="false" >
19 @hibernate.class
20 table="City"
21 </ meta >
22
23 < id
24 name ="guid"
25 type ="int"
26 column ="Guid"
27 >
28 < meta attribute ="field-description" >
29 @hibernate.id
30 generator-class="native"
31 type="int"
32 column="Guid"
33
34
35 </ meta >
36 < generator class ="native" />
37 </ id >
38
39 < property
40 name ="cityname"
41 type ="java.lang.String"
42 column ="Cityname"
43 not-null ="true"
44 length ="32"
45 >
46 < meta attribute ="field-description" >
47 @hibernate.property
48 column="Cityname"
49 length="32"
50 not-null="true"
51 </ meta >
52 </ property >
53
54 <!-- Associations -->
55
56 <!-- bi-directional many-to-one association to Province -->
57 < many-to-one
58 name ="province"
59 class ="com.xxx.hibernate.Province"
60 cascade ="none"
61 outer-join ="auto"
62 update ="true"
63 insert ="true"
64 access ="property"
65 not-null ="true"
66 >
67 < meta attribute ="field-description" >
68 @hibernate.many-to-one
69 cascade="none"
70 outer-join="auto"
71 update="true"
72 insert="true"
73 access="property"
74 not-null="true"
75 @hibernate.column name="ProvinceID"
76 </ meta >
77 < column name ="ProvinceID" />
78 </ many-to-one >
79
80 </ class >
81 </ hibernate-mapping >
82
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 永远不使用外连接来抓取关联
用hbm2java生成对应的对应的Java类:hbm2java *.xml --output=xxx。
Hibernate的配置文件hibernate.cfg.xml内容如下:
2 <! DOCTYPE hibernate-configuration
3 PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
4 "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd" >
5
6 < hibernate-configuration >
7 < session-factory >
8
9 <!-- local connection properties -->
10 < property name ="hibernate.connection.url" > jdbc:mysql://127.0.0.1/xxx?useUnicode=true & characterEncoding=UTF-8 & autoReconnect=true </ property >
11 < property name ="hibernate.connection.driver_class" > com.mysql.jdbc.Driver </ property >
12 < property name ="hibernate.connection.username" > root </ property >
13 < property name ="hibernate.connection.password" > 123456 </ property >
14 <!-- property name="hibernate.connection.pool_size"></property -->
15
16 <!-- dialect for MySQL -->
17 < property name ="dialect" > net.sf.hibernate.dialect.MySQLDialect </ property >
18
19 < property name ="hibernate.show_sql" > true </ property >
20 < property name ="hibernate.use_outer_join" > true </ property >
21 < property name ="hibernate.transaction.factory_class" > net.sf.hibernate.transaction.JDBCTransactionFactory </ property >
22
23 < mapping resource ="com/xxx/hibernate/City.hbm.xml" />
24 < mapping resource ="com/xxx/hibernate/Province.hbm.xml" />
25
26 </ session-factory >
27 </ hibernate-configuration >
JUnit的测试用例程序片断如下:
2 try {
3 Province province = new Province();
4 province.setProvincename("广东");
5
6 City city = new City();
7 city.setCityname("深圳");
8
9 city.setProvince(province);
10 province.setCities(new HashSet());
11 province.getCities().add(city);
12
13 Transaction tx = session.beginTransaction();
14 session.save(province);
15 tx.commit();
16 } catch (HibernateException e) {
17 e.printStackTrace();
18 } catch (Exception ex) {
19 ex.printStackTrace();
20 }
21 }
运行测试程序,可以看到输出了两条insert语句,省的值和市的值都插入到了表中。