hibernate 总结
配置:
一 Hibernate基本映射:
类-->数据库表
普通属性--> 表字段
通过<class>标签映射到数据库表,通过<property>标签将普通属性映射到表字段
所谓普通属性,不包括自定义类,集合类和数组等。
实体类四条主要的规则:
* 实现一个默认的(即无参数的)构造方法(constructor)
* 提供一个标识属性(identifier property)(可选)
* 使用非final的类 (可选)
* 为持久化字段声明访问器(accessors)(可选)
<class>标签用来将一个类映射到数据库表,其name属性表示这个类的全路径,默认情况下,
映射到数据库表名,与类名相同。我们可以通过<class>标签的table属性更改表的名称
!!注意:如果类的名称是数据库的关键字,则必须通过table属性来重新定义对应的表名;
类属性的映射包括:
* 普通属性
* 自定义属性
* 集合(数组)
ID的映射:
了解id的生成策略,重点了解uuid、native、assigned
------------------
<?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="com.bjsxt.hibernate.User1" table="t_user1">
<id name="id">
<generator class="uuid"/>
<!--
<generator class="native"/>
oracle会自动指定sequence为自增长
<generator class="assigned"/>手动
-->
</id>
<property name="name" length="20" unique="true"/>
<property name="password"/>
<property name="createTime"/>
<property name="expireTime"/>
</class>
</hibernate-mapping>
Hibernate一对多单向关联映射
<set name="students" inverse="true" orderby="asfd"><!-- 在表现层可以有稳定的输出-->
<key column="classid"/>
<one-to-many class="com.bjsxt.hibernate.Student"/>
</set>
这种映射的本质是利用了多对一的关联映射的原理
多对一关联映射:是在多的一端添加一个外键维护多指向一的关联引用
一对多关联映射:是在多的一端添加一个外键维护一指向多的关联引用
也就是说,一对多和多对一的映射策略是一致的,只是站的角度不同
缺点:
* 更新student表中的classesid字段时,需要对每一个student发出一个update的sql,
来更新classesid字段
* 如果将t_student表中的classesis设置为非空,则不能保存student数据,因为关系是由
classes维护的,在保存student时,还没有对应的classesid被生成
Hibernate 一对多双向关联映射
一对多双向关联映射的方法:
在一一端:
在集合标签里面使用<key>标签来表明需要在对方的表中添加一个外键指向一一端。
在多一端:
使用<many-to-one>标签来映射。
需要注意:<key>标签所指定的外键字段名需要与<many-to-one>标签定义的外键字段名一致,否则便会造成引用数据的
丢失!
--------------------------------------------------------------------------------------
如果从一端来维护一对多双向关联的关系,hibernate会发出多余的update语句,所以
一般地情况下,我们便会从多一端来维护其关联关系!
----------------------------------------------------
关于inverse属性:
inverse属性可以被设置到集合标签<set>上,表示在存储双向一对多关联映射的时候,
存储的是那一方的关联引用。默认情况下,inverse=“false”,所以,我们可以从一一端
或者多一端来维护两者之间的关系;如果我们设置inverse=“true”,则只能通过多一端来
维护两者之间的关系。inverse属性可以被用在一对多和多对多双向关联中;
注意:inverse属性只是在将数据持久化到数据库的过程中发挥作用.
多的一方维护没有了UPDATE
一的一方维护先insert后update
使用inverse后如果还用一的一维护db中就会有null,持久化就不成功。 也就说使用了inverse=true后只能从一的一方来维护,所谓维护就是,谁使用setXXXX方法,即student.setClass(class1);
Hibernate多对一关联
关联映射的本质
* 是将关联关系映射到数据库中,关联关系在对象模型中体现为内存中的一个或多个引用
<many-to-one>标签会在“多”的一端添加一个外键,指向“一”的一端,这个外键是由<many-to-one>
标签中的column属性定义的,如果忽略column属性,默认创建的外键与属性名相同
<many-to-one>标签的定义实例:
<many-to-one name="group" column="relatedGroup"/>
可以指定class属性,如果不指定Hibernate会自动找其关联类
理解级联的含义 casecade=update-delete all等 使用casecade设置可避免抛出非持久化异常
Hibernate一对一主键关联映射(双向关联)
<one-to-one>不会在表中添加新的列
<hibernate-mapping>
<class name="com.bjsxt.hibernate.Person" table="t_person">
<!-- 主键一致 要引对方的主键 -->
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person"/>
</class>
</hibernate-mapping>
Hibernate一对一外键关联映射(双向关联)
<hibernate-mapping>
<class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person" property-ref="idCard" /><!-- 根据person中的属性idCard来确定 -->
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.bjsxt.hibernate.Person" table="t_person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
多对多单向关联
要有中间表来引入,有时在设计时也可在中间表中入其它列
需要注意映射规则:
<set name="users" table="t_user_role">
<key column="roleid"/><!--中间表-->
<many-to-many class="com.bjsxt.hibernate.User" column="userid"/>
</set>
多对多双向关联
注意映射规则:
<set name="roles" table="t_user_role">
<key column="userid"/>
<many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
</set>
table属性必须和单向关联中table的 名称相同;
<key>中的column属性值必须等于单向关联中<many-to-many>标签指向的column的属性值
<many-to-many>中column属性值必须等于单向关联中<key>中column的属性值
在user_role模式中也使用单向的many-to-one(inverse)映射,由中间表指向user 和 role 来维护多对多的情况
Hibernate继承映射
Hibernate继承映射的第一种策略:每棵类继承树对应一张表
1、理解如何映射
因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。
这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
父类用普通的<class>标签定义
在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
如:<discriminator column=”XXX” type=”string”/>
子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:
Subclass标签的name属性是子类的全路径名
在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值
Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。
当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在subclass标签的内部。
2、理解如何存储
在存储数据的时候,hibernate会自动将鉴别字段的值插入到数据库中,在加载数据的时候,
hibernate便能根据这个鉴别字段正确的加载对象
3、理解何为多态查询,即hibernate能够加载数据的时候自动鉴别其真正的类型(class参数类型), instanceof 返回false 代理的原因
//因为我们load默认是Lazy,因为Lazy所以我们看到的是Animal的代理类
//所以通过instance是具体反映不
多态get(),支持
多态load(),设置Lazy=“false”时,支持
多态查询,支持
Hibernate继承映射的第二种策略:每个类对应一张表
1、如何映射
这种策略是使用joined-subclass标签来定义子类的。父类、子类,每个类都对应一张数据库表。
在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,
这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。实现这种策略的时候,有如下步骤:
父类用普通的<class>标签定义即可
父类不再需要定义discriminator字段
子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:
Joined-subclass标签的name属性是子类的全路径名
Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。
Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),
也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,需要在Joined-subclass标签中,添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。
2、存储和多态查询参见策略一:每棵类继承树对应一张表
Hibernate继承映射的第三种策略:每个具体类一张表
1、如何映射
这种策略是使用union-subclass标签来定义子类的。每个子类对应一张表,而且这个表的信息是完备的,
即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,joined-subclass定义的子类的表,
只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:
父类用普通<class>标签定义即可
子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:
Union-subclass标签不再需要包含key标签(与joined-subclass不同)
Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),
也可以与class标签平行。 当Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass标签中,添加extends属性,里面的值是父类的全路径名称。
子类的其它属性,像普通类一样,定义在Union-subclass标签的内部。这个时候,虽然在union-subclass里面定义的只有子类的属性,但是因为它继承了父类,所以,
不需要定义其它的属性,在映射到数据库表的时候,依然包含了父类的所有属性的映射字段。
!!!特别注意:在保存对象的时候,id不能重复(所以不能用自增方法生成主键)
2、存储和多态查询参见策略一:每棵类继承树对应一张
集合的映射
set
list
array
map
<hibernate-mapping>
<class name="com.bjsxt.hibernate.CollectionMapping" table="t_collection_mapping">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="setValues" table="t_set_values">
<key column="set_id"/>
<element type="string" column="set_value"/>
</set>
<list name="listValues" table="t_list_values">
<key column="list_id"/>
<list-index column="list_index"/><!-- 有序的-->
<element type="string" column="list_value"/>
</list>
<array name="arrayValues" table="t_array_values">
<key column="array_id"/>
<list-index column="array_index"/><!-- 有序的-->
<element type="string" column="array_value"/>
</array>
<map name="mapValues" table="t_map_values">
<key column="map_id"/>
<map-key type="string" column="map_key"/>
<element type="string" column="map_value"/>
</map>
</class>
</hibernate-mapping>
component(组件映射)
在hibernate中,component是某个实体对象的逻辑组成部分,它与实体的根本区别是
component是没有标识的,它是一个逻辑组成部分,完全从属于某个实体
这样就在传统数据库上,实现了对象的细粒度划分,层次分明,实现了面向对象的领域划分
<hibernate-mapping>
<class name="com.bjsxt.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="contact">
<property name="address"/>
<property name="contactTel"/>
<property name="email"/>
<property name="zipCode"/>
</component>
</class>
</hibernate-mapping>
复合主键映射
通常将复合主键相关属性,单独抽取出来,建立一个独立的类
* 必须实现序列化接口
* 必须实现equals和hashcode方法
采用<composite-id>标签进行映射,其它属性采用<property>正常映射
<hibernate-mapping>
<class name="com.bjsxt.hibernate.FiscalYearPeriod" table="t_fiscal_year_period">
<composite-id name="fiscalYearPeriodPK">
<key-property name="fiscalYear" column="fiscal_year"/>
<key-property name="fiscalPeriod" column="fiscal_period"/>
</composite-id>
<property name="beginDate" column="begin_date"/>
<property name="endDate" column="end_date"/>
<property name="periodSts" column="period_sts"/>
</class>
</hibernate-mapping>
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
操作:
理解通过session接口进行CRUD的基本操作方法。
get和load的区别?
Transient对象具有的特征:
* 不处于session缓存中,不被任何一个session实例关联
* 在数据库中没有相应的记录
persistent对象具有的特征:
* 位于一个Session的缓存中,持久对象总是和一个session实例关联
* 持久对象和数据库中的记录对应
* 持久对象的变化会自动同步到数据库
detached对象具有的特征:
* 不再位于session的缓存中,不被session关联
* detached对象是由persistent对象转变过来的,因此数据库中会存在一条记录与之对应
Hibernate hql
* 注意hql的大小写敏感性
1、实体对象的查询,查询的是实体对象的数据【重要】
* n+1问题,在默认配置的情况下,使用query.iterate()操作,有可能有n+1问题,所谓
n+1,指在查询对象数据的时候,发出了n+1条查询语句。
1:首先发出了一条查询语句,查询对象的id列表
n:在迭代访问每个对象的时候,如果缓存中没有对象数据,Hibernate会在此发出一条查询语句,
查询相应的对象
*List操作与Iterate操作的区别
list,每次都会发出一条查询语句,查询所有的对象
iterate,首先发出一条查询语句,查询对象的id列表,然后根据缓存情况,决定
是否发出更多的查询语句,来查询对象数据
参见:SimpleObjectQueryTest2.java
2、简单属性查询 在调优上与查询缓存相关
* 单个属性查询,返回的结果集属性的列表,其元素和属性的类型一致
* 多个属性查询,返回的结果集是数组类型,数组的长度和查询的属性数量相关,数组中元素的类型与相应的属性类型相同
//查询多个属性,其集合元素是对象数组
//数组元素的类型,跟实体类的属性的类型相关
List students = session.createQuery("select id, name from Student").list();
for (Iterator iter = students.iterator();iter.hasNext();) {
Object[] obj = (Object[])iter.next();
System.out.println(obj[0] + ", " + obj[1]);
}
3、条件查询【重要】
* 可以拼字符串的形式传递参数
* 可以用过?来传递参数(注意索引值是从0开始的,跟jdbc不同,jdbc是从1开始的)
* 可以通过 :参数名 来传递参数(即命名参数方式)
* 如果对应的参数值是多个,可以调用setParamterList()方法开传递
* 在HQL中可以使用数据库的函数,如date_format()
//条件查询,拼字符串
List students = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE '%1%'").list();
//条件查询,使用 ? 的方式传递参数
Query query = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE ?");
//传递参数
//参数的索引是从0开始的
//传递的字符串,无需用''单引号括起来
query.setParameter(0, "%1%");
List students = query.list();
//条件查询,使用 :参数名称 的方式传递参数
Query query = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE :myname");
//传递参数
query.setParameter("myname", "%1%");
List students = query.list();
//条件查询,支持in,需要用setParameterList()进行参数传递
List students = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.id in(:myids)")
.setParameterList("myids", new Object[]{1, 3, 5})
.list();
List students = session.createQuery("SELECT s.id, s.name FROM Student s WHERE " + "substring(s.createTime, 1, 7) =?")
.setParameter(0, "2007-01")
.list();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
List students = session.createQuery("SELECT s.id, s.name FROM Student s WHERE " +
"s.createTime between ? and ? ")
.setParameter(0, format.parseObject("2007-01-01"))
.setParameter(1, format.parseObject("2007-03-01"))
.list();
4、hibernate也支持直接使用原生sql进行查询
参见:SqlQueryTest.java
5、外置的命名查询
* 在映射文件中通过<query>标签定义hql
* 在程序中使用session.getNameQuery()方法获得这个查询
参见:Student.hbm.xml,NameQueryTest.java
6、查询过滤器
* 定义过滤器参数
* 在类映射文件中使用这些参数
* 在session中启用过滤器
参见:Student.hbm.xml,FilterQueryTest.java
7、对象导航查询,在HQL语句中,可以使用.的方式进行对象导航【重要】
参见:ObjectNavQueryTest.java
8、连接查询(在对象里可以直接导航)【重要】
* 内连接
* 外连接(左连接/右连接)
内连接,从Student连接到Classes: List students = session.createQuery("select c.name, s.name from Student s join s.classes c ").list();
左外连接:List students = session.createQuery("select c.name, s.name from Classes c left join c.students s ").list();
右外连接:List students = session.createQuery("select c.name, s.name from Classes c right join c.students s ").list();
9、统计查询
List students = session.createQuery("select count(*) from Student").list();
10、分页查询【重要】
* 通过query接口中的setFirstResult()和setMaxResults() 进行分页
Query query = session.createQuery("from Student");
query.setFirstResult(27);
query.setMaxResults(5);
List students = query.list();
11、DML风格的操作(尽量)
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
----------------
hibernate性能调优
缓存的设置 主要是减少对数据的访问次数 包括 query session sessionfactory
hibernate查询缓存 不常用
配置:
在hibernate.cfg.xml文件中加入:<property name="hibernate.cache.use_query_cache">true</property>
1、针对普通属性结果集的缓存
2、对是实体对象的结果集,只缓存id
3、使用查询缓存,需要打开查询缓存,并且在调用list方法之前需要显示的调用query.setCacheable(true);
session一级缓存
1、一级缓存很短,和session的生命周期一致,随着session的关闭而消失
*load/get/iterate(查询实体对象)可以使用缓存数据
2、一级缓存它缓存的是实体对象
3、如果管理缓存,如session.clear()/session.evict()
4、如何避免一次性大批量实体数据插入内存溢出的问题?
*先执行flush,在用clear清除缓存
一级缓存的管理
/**
* 向数据库中插入10000学生数据
session.flush();
session.clear();
*
*/
public void testCache8() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
for (int i = 0; i < 10000; i++) {
Student student = new Student();
student.setName("Student_" + i);
session.save(student);
//每100条数据就强制session将数据持久化
//同时清空缓存,以避免在大量的数据下,造成内存溢出
if ( i % 100 == 0) {
session.flush();
session.clear();
}
}
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
hibernate二级缓存
定义步骤:
1、打开缓存,在hibernate.cfg.xm中加入:
<property name="hibernate.cache.use_second_level_cache">true</property>
2、指定缓存策略提供商,在hibernate.cfg.xm中加入:
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3、拷贝echcahe.xml到src下,可以针对不同的策略配置缓存
4、指定那些类使用缓存(两种方式)
* 在hibernate.cfg.xml
* 在映射文件中
二级缓存中存储的也是实体对象,他们都属于SessionFactory级别,
是全局的,伴随SessionFactory的生命周期存在和消亡 在WEB开发中应该是所有用户共享的 对相应的缓存类的设置要注意使用
需要了解一级缓存和二级缓存的交互模式(CacheMode)先一级后二级
二抓取策略
Hibernate抓取策略
在单端映射(many-to-one or one-to-one)情况下:
1,默认fetch的配置,也就fetch="select",如:
<many-to-one name="classes" column="classid" fetch="select" />
由于默认lazy在对象导航时,引用一个对象的数据就发一sql语句
2,设置fetch="join",如:
<many-to-one name="classes" column="classid" fetch="join" />
与select策略相比只发一条sql语句
但是会导致lazy失效
对方是集合的情况下情况下:
<set name="students" inverse="true" fetch="select">
<key column="classid"/>
<one-to-many class="com.wanye.Student"/>
</set>
在用到集合中对象的数据时,用一个发一条
设置fetch=“join”,参见:Classes.hbm.xml,如:
<set name="students" inverse="true" fetch="join">
发一条sql语句 带有join;
但会导致lazy失效
设置fetch=“subselect”,参见:Classes.hbm.xml,如:
<set name="students" inverse="true" fetch="subselect">
public void testFetch2() {
Session session = null;
try {
session = HibernateUtils.getSession();
List Classes = session.createQuery("select c from Classes c where c.id in(1, 2, 3)").list();
for (Iterator iter = Classes.iterator(); iter.hasNext();) {//发出一条带有子查询的sql语句
Classes cls = (Classes)iter.next();
System.out.println("班级:" + cls.getName());
for (Iterator iter1 = cls.getStudents().iterator(); iter1.hasNext();) {
Student student = (Student)iter1.next();
System.out.println(student.getName());
}
}
}catch(Exception e) {
e.printStackTrace();
}finally {
HibernateUtils.closeSession(session);
}
}
在用到集合中对象的数据时,发出一条带有子查询的sql语句
batch策略,两种方式
针对fetch="select"配置进行优化,在类映射上加入batch,如:
<class name="com.bjsxt.hibernate.Classes" table="t_classes" batch-size="5">
在集合上设置batch
<set name="students" inverse="true" batch-size="5">
在用到集合中对象的数据时,每5个对象发出一条sql语句,防止缓存溢出。
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
附:
<!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.connection.url">jdbc:mysql://127.0.0.1/databasename</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 是否启用二级缓存
1、打开缓存,在hibernate.cfg.xm中加入:
<property name="hibernate.cache.use_second_level_cache">true</property>
2、指定缓存策略提供商,在hibernate.cfg.xm中加入:
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3、拷贝echcahe.xml到src下,可以针对不同的策略配置缓存
4、指定那些类使用缓存(两种方式)
* 在hibernate.cfg.xml
* 在映射文件中
二级缓存中存储的也是实体对象,他们都属于SessionFactory级别,
是全局的,伴随SessionFactory的生命周期存在和消亡
需要了解一级缓存和二级缓存的交互模式(CacheMode)
-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 设置缓存策略提供商 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 设置查询缓存
1、针对普通属性结果集的缓存
2、对是实体对象的结果集,只缓存id
3、使用查询缓存,需要打开查询缓存,并且在调用list方法之前需要显示的调用query.setCacheable(true);
-->
<property name="hibernate.cache.use_query_cache">true</property>
<mapping resource="com/bjsxt/hibernate/Classes.hbm.xml"/>
<mapping resource="com/bjsxt/hibernate/Student.hbm.xml"/>
<!-- 指定那些类使用缓存
usage="read-only" 即可 主要缓存那些不常变化的,最发设置成read-only
-->
<class-cache class="com.bjsxt.hibernate.Student" usage="read-only"/>
</session-factory>
</hibernate-configuration>
树的映射:
<?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="com.bjsxt.hibernate.Node" table="t_node">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="level"/>
<property name="leaf"/>
<many-to-one name="parent" column="pid"/>
<set name="children" lazy="extra">
<key column="pid"/>
<one-to-many class="com.bjsxt.hibernate.Node"/>
</set>
</class>
</hibernate-mapping>