- 浏览: 141456 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
aa87963014:
很好,但是update/insert 是否加锁 。加锁对sel ...
数据库锁 -
RobustTm:
我的这种做法也可以添加A和B
但是换成更新就有问题
hibernate入门(十一):级联操作inversin属性 -
RobustTm:
这位仁兄可以提供一对多双向关联完整的代码不?
我碰到了问题,采 ...
hibernate入门(十一):级联操作inversin属性 -
cfeers:
markxing 写道谢谢分享。。。
不客气,呵呵。
struts2.0 struts.xml配置文件详解 -
markxing:
谢谢分享。。。
struts2.0 struts.xml配置文件详解
十二、一些细节问题分析
1.实体配置文件中的类型问题:
在前面的多个实例中配置<property>映射类型时,我们都采取的是hibernate默认的配置,即是说没有在<property>中配置type属性:其实基本类型一般不需要映射文件中配置,只有在一个java类型与多个数据库类型相对应时,交且我们不希望使用默认的配置才会用type来指明类型。举例:java.util.Date与数据库中的DATE,TIME,DATETIME,TIMESTAMP相对应,如果我们不希望映射成默认的DATATIME,而想映成DATE,便配置成type=“DATE”,另需要说明的是我们也可配置成我们自定义的类型,但前提是我们自定义的类型必须实现org.hibernate.UserType或org.hibernate.CompositeUserType中的任何一个接口。且在配置时指定类的完整名。
2.Session与SessionFactory:
Session是非线程安全的,生命周期较短,代表一个数据库的连接,在B/S系统中一般不会超过一个请求,内部维护一级缓存和数据库连接。通常一个Session的生成也就意味着即将结束。
SessionFactory是线程安全的,一个数据库对应一个SessionFactoy,一般会在整个系统生命周期内有效:SessionFactory保存着和数据库连接相关的信息(user,password,url)和映射信息,以及hibernate运行时用到的一些信息。
3.Session中的flush方法:
此方法的作用是将一级缓存与数据库同步,通常在查询数据或者是提交前(可能会采取批量更新的方式到数据库)会实现同步,这样可有效保证一级缓存中的数据是有效的数据。这个方法是由hibernate自身来维护调用的,因为它的调用意味着与数据库交互,所以不建议我们手工调用,而事实上hibernate对它的调用主要是为了提升性能和保证数据的有效性且hibernate自身的对它的维护调用已近完美。
4.巧用flush解决内存溢出问题:
当我们进行类似如下的操作时:for (int i = 0; i < 10000000; i++) s.save(obj);当i足大到我们的内存不足以承受时,便会出现内存溢出问题,对于此可以这样解决:
for (int i = 0; i < 10000000; i++) {
s.save(obj);
if (i % 30 == 0) {
s.flush();
s.clear();
}
} 分析:当每保存30个数据时,我们便清掉一级缓存中的内容,但是在清掉内容前我们必须让一级缓存中的数据与数据库进行一次交互,这样可以保证数据能被保存到数据库中。试想下,如果不flush,那么在一级缓存中的数据是不能同步到数据库中的,所以这里flush是非常重要得。 其实只要再来回忆前面所说的一级缓存中的一些知识,便可以发现如果保存的对象的主键是以increme的方式生成的,可以不用flush也能实现数据及时同步到数据库中。
5.用StatelessSession接口解决批量更新问题:
在进行如上的批量操作时,我们通过flush来解决和数据库的同步更新,但是这样会造成缓存的不断更新,因此在进行类似的批量操作时,我们通常会选择使用StatelessSession接口来代替Session,由于这种无状态的Session具有以下特点:它不和一级缓存、二级缓存交互,也不触发任何事件,监听器,拦截器,通过该接口能把这些批量更新直接发送到数据库。说明:StatelessSession的方法也Session的方法相似。 除了此方法外,我们使用Query.executeUpdate(),也可以执行批量更新,但是此方法会清除相关联的类的二级缓存,也可能造成级联,甚至是和乐观锁不相容。
6.离线查询DetachedCriteria:
package com.asm.hibernate.test; public class DetachedCriteriaTest { public static void main(String[] args) { add(); DetachedCriteria dec = DetachedCriteria.forClass(User.class); String name = "jack"; dec.add(Restrictions.eq("name", name)); List<User> list = detaCri(dec); for (User u : list) System.out.println(u); } static List detaCri(DetachedCriteria dec) { Session s = HibernateUtil.getSession(); Criteria cr = dec.getExecutableCriteria(s); List list = cr.list(); s.close(); return list; } static void add() { ...省略内容:主要作用是在数据库中插入两条名为“jack”的记录,以使查询操作可以进行。 } }
分析:为会么要使用这种离线查询,比如我们可以在业务逻辑层构造出一个DetachedCriteria对象,且它不会依赖于Session,这样当们把这个对象作为参数来传递给M层的方法时便可以实现连库查询。这样可以有效的使用Session,避免与数据库的频繁交互。
7.监听器的使用:
下面首通过一个简单的例子来说明此问题:
>>步骤一、编写监听类:
package com.asm.hibernate.event; public class SaveUserListener implements SaveOrUpdateEventListener { public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { if (event.getObject() instanceof com.asm.hibernate.domain.User) { User user = (User) event.getObject(); System.out.println("find save User:" + user.getName()); user.setDate(new Date()); } } }
分析:当有保存/更新事件发生时,便被此监听类监听到,而我们处理的只是保存/更新User对象,即是说当发生保存/更新一个User对象时,才会被这个监听器监听操作;其它对象的保存/更新操作尽管也会被它监听,但不会有处理动作。
>>步骤二、编写测试类:
package com.asm.hibernate.event; public class TestListener { public static void main(String[] args) { addUser(); } static void addUser() { Session s = null; Transaction tx = null; try { User u = new User(); u.setName("jack"); s = HibernateUtil.getSession(); tx = s.beginTransaction(); s.save(u); tx.commit(); } finally { if (s != null) s.close(); } } }
分析:执行后,发现没有任何作用。原因是未配置监听器,联想到gui程序监听时,总会在程序中给出相应的代码,而这里我们只需要在主配置文件中配置这个监听器,在由hibernate把这个监听器写成代码到程序中去。在主配置文件中配置的内容如下:
这样配置后,尽管监听器类中的方法能实现,但是发现这些数据没有保存到数据库中。因为当们配置一监听器时,相对应的默认监听器就失效了,即是说org.hibernate.event.def.DefaultSaveOrUpdateEventListener这个默认的监听器不起作用了,为了能继续使用默认的监听器,应再配置上这个监听器,即配置成这样:
<event type="save"> <listener class="com.asm.hibernate.event.SaveUserListener" /> <listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener" /> </event>
这样配置后,即可以让我们自己的监听器生效,又可以让默认监听器起作用。
8.使用原始的sql查询:
代码如下:
package com.asm.hibernate.test; public class JdbcSqlSelectTest { public static void main(String[] args) { addUsers(); query(); } static void query() { Session s = HibernateUtil.getSession(); Query q = s.createSQLQuery("select * from user").addEntity(User.class); List<User> rs = q.list(); for (User u : rs) { System.out.println("Result:"+u.getName() + "---" + u.getDate()); } } static void addUsers() { ...增加一些记录,以检验查询 } }
分析:关键是看查询方法:中间用到的查询语句from user,user是指表名,后面增加addEntity方法的主要是了了保证返回的list对象中保存的User,这样方便foreach遍历。 需要说明的是尽管hibernate支持这种sql查询,但是它不具有通用性,即是说我们在写这些查询语句时总会依赖于一个具体的数据库,一旦换了数据库就可能出现问题,因此最好不要使用这种JdbcSql查询。
9.命名查询:
>>步骤一:在User的实体配置文件</hibernate-mapping>的元素下增加如下内容:
<query name="selectUserbyId"> <![CDATA[from User where id=:id]]> </query>
>>步骤二、编写测试:
static List namedQuery(int id) { Session s = HibernateUtil.getSession(); Query q = s.getNamedQuery("selectUserbyId"); //Query q=s.getNamedQuery("com.asm.hibernate.domain.User.selectUserbyIdTheSecond"); q.setInteger("id", id); return q.list(); }
说明:这种方式虽然简单,但是容易在整个系统中引起重名,所以最好的方式是在Use的实体配置文件的<class>元素下配置这个属性,比如我们在<class>元素的最后增加如下内容:
<query name="selectUserbyIdTheSecond"> <![CDATA[from User where id=:id]]> </query>
则在上面的代码中要想用到这个命名查询,则应写成注释掉的代码那样。如果项目中的命名查询不多,建议写在</hibernate-mapping>元素下,这样引用较方便。
补充说明:我们也可以配置SQl的命名查询,步骤是先在</hibernate-mapping>元素下配置如下内容:
<sql-query name="selectUserSql"> <![CDATA[select * from user]]> </sql-query>
然后执行下面的代码:
static List namedSqlQuery(int id) { Session s = HibernateUtil.getSession(); Query q = s.getNamedQuery("selectUserSql"); return q.list(); }
10.N+1查询:
N+1查询:由于缓存,或者lazyload(懒加载)等原因,在查询n个结果,可能要执行n+1次查询数据库操作。 在Hibernate的N+1查询主要表现在:(1)使用iterate查询的时候 (2)查询子对象的时候。其实N+1曾引发了关于效率上的讨论,因此建议到网上查阅有关的资料学习。
11.HQL 、QBC:
在前面曾应用过HQL,QBC,所以对于它们的进一步学习,应该很容易上手,所以同样建议参看官方手册或者查阅其它相关资料进行更深入的学习。
1.实体配置文件中的类型问题:
在前面的多个实例中配置<property>映射类型时,我们都采取的是hibernate默认的配置,即是说没有在<property>中配置type属性:其实基本类型一般不需要映射文件中配置,只有在一个java类型与多个数据库类型相对应时,交且我们不希望使用默认的配置才会用type来指明类型。举例:java.util.Date与数据库中的DATE,TIME,DATETIME,TIMESTAMP相对应,如果我们不希望映射成默认的DATATIME,而想映成DATE,便配置成type=“DATE”,另需要说明的是我们也可配置成我们自定义的类型,但前提是我们自定义的类型必须实现org.hibernate.UserType或org.hibernate.CompositeUserType中的任何一个接口。且在配置时指定类的完整名。
2.Session与SessionFactory:
Session是非线程安全的,生命周期较短,代表一个数据库的连接,在B/S系统中一般不会超过一个请求,内部维护一级缓存和数据库连接。通常一个Session的生成也就意味着即将结束。
SessionFactory是线程安全的,一个数据库对应一个SessionFactoy,一般会在整个系统生命周期内有效:SessionFactory保存着和数据库连接相关的信息(user,password,url)和映射信息,以及hibernate运行时用到的一些信息。
3.Session中的flush方法:
此方法的作用是将一级缓存与数据库同步,通常在查询数据或者是提交前(可能会采取批量更新的方式到数据库)会实现同步,这样可有效保证一级缓存中的数据是有效的数据。这个方法是由hibernate自身来维护调用的,因为它的调用意味着与数据库交互,所以不建议我们手工调用,而事实上hibernate对它的调用主要是为了提升性能和保证数据的有效性且hibernate自身的对它的维护调用已近完美。
4.巧用flush解决内存溢出问题:
当我们进行类似如下的操作时:for (int i = 0; i < 10000000; i++) s.save(obj);当i足大到我们的内存不足以承受时,便会出现内存溢出问题,对于此可以这样解决:
for (int i = 0; i < 10000000; i++) {
s.save(obj);
if (i % 30 == 0) {
s.flush();
s.clear();
}
} 分析:当每保存30个数据时,我们便清掉一级缓存中的内容,但是在清掉内容前我们必须让一级缓存中的数据与数据库进行一次交互,这样可以保证数据能被保存到数据库中。试想下,如果不flush,那么在一级缓存中的数据是不能同步到数据库中的,所以这里flush是非常重要得。 其实只要再来回忆前面所说的一级缓存中的一些知识,便可以发现如果保存的对象的主键是以increme的方式生成的,可以不用flush也能实现数据及时同步到数据库中。
5.用StatelessSession接口解决批量更新问题:
在进行如上的批量操作时,我们通过flush来解决和数据库的同步更新,但是这样会造成缓存的不断更新,因此在进行类似的批量操作时,我们通常会选择使用StatelessSession接口来代替Session,由于这种无状态的Session具有以下特点:它不和一级缓存、二级缓存交互,也不触发任何事件,监听器,拦截器,通过该接口能把这些批量更新直接发送到数据库。说明:StatelessSession的方法也Session的方法相似。 除了此方法外,我们使用Query.executeUpdate(),也可以执行批量更新,但是此方法会清除相关联的类的二级缓存,也可能造成级联,甚至是和乐观锁不相容。
6.离线查询DetachedCriteria:
package com.asm.hibernate.test; public class DetachedCriteriaTest { public static void main(String[] args) { add(); DetachedCriteria dec = DetachedCriteria.forClass(User.class); String name = "jack"; dec.add(Restrictions.eq("name", name)); List<User> list = detaCri(dec); for (User u : list) System.out.println(u); } static List detaCri(DetachedCriteria dec) { Session s = HibernateUtil.getSession(); Criteria cr = dec.getExecutableCriteria(s); List list = cr.list(); s.close(); return list; } static void add() { ...省略内容:主要作用是在数据库中插入两条名为“jack”的记录,以使查询操作可以进行。 } }
分析:为会么要使用这种离线查询,比如我们可以在业务逻辑层构造出一个DetachedCriteria对象,且它不会依赖于Session,这样当们把这个对象作为参数来传递给M层的方法时便可以实现连库查询。这样可以有效的使用Session,避免与数据库的频繁交互。
7.监听器的使用:
下面首通过一个简单的例子来说明此问题:
>>步骤一、编写监听类:
package com.asm.hibernate.event; public class SaveUserListener implements SaveOrUpdateEventListener { public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { if (event.getObject() instanceof com.asm.hibernate.domain.User) { User user = (User) event.getObject(); System.out.println("find save User:" + user.getName()); user.setDate(new Date()); } } }
分析:当有保存/更新事件发生时,便被此监听类监听到,而我们处理的只是保存/更新User对象,即是说当发生保存/更新一个User对象时,才会被这个监听器监听操作;其它对象的保存/更新操作尽管也会被它监听,但不会有处理动作。
>>步骤二、编写测试类:
package com.asm.hibernate.event; public class TestListener { public static void main(String[] args) { addUser(); } static void addUser() { Session s = null; Transaction tx = null; try { User u = new User(); u.setName("jack"); s = HibernateUtil.getSession(); tx = s.beginTransaction(); s.save(u); tx.commit(); } finally { if (s != null) s.close(); } } }
分析:执行后,发现没有任何作用。原因是未配置监听器,联想到gui程序监听时,总会在程序中给出相应的代码,而这里我们只需要在主配置文件中配置这个监听器,在由hibernate把这个监听器写成代码到程序中去。在主配置文件中配置的内容如下:
这样配置后,尽管监听器类中的方法能实现,但是发现这些数据没有保存到数据库中。因为当们配置一监听器时,相对应的默认监听器就失效了,即是说org.hibernate.event.def.DefaultSaveOrUpdateEventListener这个默认的监听器不起作用了,为了能继续使用默认的监听器,应再配置上这个监听器,即配置成这样:
<event type="save"> <listener class="com.asm.hibernate.event.SaveUserListener" /> <listener class="org.hibernate.event.def.DefaultSaveOrUpdateEventListener" /> </event>
这样配置后,即可以让我们自己的监听器生效,又可以让默认监听器起作用。
8.使用原始的sql查询:
代码如下:
package com.asm.hibernate.test; public class JdbcSqlSelectTest { public static void main(String[] args) { addUsers(); query(); } static void query() { Session s = HibernateUtil.getSession(); Query q = s.createSQLQuery("select * from user").addEntity(User.class); List<User> rs = q.list(); for (User u : rs) { System.out.println("Result:"+u.getName() + "---" + u.getDate()); } } static void addUsers() { ...增加一些记录,以检验查询 } }
分析:关键是看查询方法:中间用到的查询语句from user,user是指表名,后面增加addEntity方法的主要是了了保证返回的list对象中保存的User,这样方便foreach遍历。 需要说明的是尽管hibernate支持这种sql查询,但是它不具有通用性,即是说我们在写这些查询语句时总会依赖于一个具体的数据库,一旦换了数据库就可能出现问题,因此最好不要使用这种JdbcSql查询。
9.命名查询:
>>步骤一:在User的实体配置文件</hibernate-mapping>的元素下增加如下内容:
<query name="selectUserbyId"> <![CDATA[from User where id=:id]]> </query>
>>步骤二、编写测试:
static List namedQuery(int id) { Session s = HibernateUtil.getSession(); Query q = s.getNamedQuery("selectUserbyId"); //Query q=s.getNamedQuery("com.asm.hibernate.domain.User.selectUserbyIdTheSecond"); q.setInteger("id", id); return q.list(); }
说明:这种方式虽然简单,但是容易在整个系统中引起重名,所以最好的方式是在Use的实体配置文件的<class>元素下配置这个属性,比如我们在<class>元素的最后增加如下内容:
<query name="selectUserbyIdTheSecond"> <![CDATA[from User where id=:id]]> </query>
则在上面的代码中要想用到这个命名查询,则应写成注释掉的代码那样。如果项目中的命名查询不多,建议写在</hibernate-mapping>元素下,这样引用较方便。
补充说明:我们也可以配置SQl的命名查询,步骤是先在</hibernate-mapping>元素下配置如下内容:
<sql-query name="selectUserSql"> <![CDATA[select * from user]]> </sql-query>
然后执行下面的代码:
static List namedSqlQuery(int id) { Session s = HibernateUtil.getSession(); Query q = s.getNamedQuery("selectUserSql"); return q.list(); }
10.N+1查询:
N+1查询:由于缓存,或者lazyload(懒加载)等原因,在查询n个结果,可能要执行n+1次查询数据库操作。 在Hibernate的N+1查询主要表现在:(1)使用iterate查询的时候 (2)查询子对象的时候。其实N+1曾引发了关于效率上的讨论,因此建议到网上查阅有关的资料学习。
11.HQL 、QBC:
在前面曾应用过HQL,QBC,所以对于它们的进一步学习,应该很容易上手,所以同样建议参看官方手册或者查阅其它相关资料进行更深入的学习。
发表评论
-
hibernate.cfg.xml文件详解(annotation 配置)
2010-08-26 15:57 1570一、 环境搭建和基本映 ... -
hibernate.cfg.xml文件详解
2010-08-26 15:56 746<?xml version='1.0' encoding ... -
hiberante入门(十七):简要总结及源码文档
2010-08-26 11:28 696十三、总结: 1.主配置与实体(映射)配置: 关于这些配置 ... -
hiberante入门(十五):事务相关-悲观乐观锁
2010-08-26 11:25 11801.事务引发的三层架构MV ... -
hiberante入门(十四):缓存2
2010-08-26 11:24 433>>步骤四、测试二 ... -
hiberante入门(十四):缓存1
2010-08-26 11:10 7651.模拟缓存并简要说明缓存实现原理 在myhibernate ... -
hiberante入门(十三):懒加载
2010-08-26 11:07 9364.懒加载: 在前面我们已经对懒加载有所提及,现在再借助一个 ... -
hiberante入门(十二):继承关系2
2010-08-26 11:03 985上接hiberante入门(十二 ... -
hiberante入门(十二):继承关系1
2010-08-26 11:01 8473.继承关系: 在前面的部门员工实例中,我们设定的员工只是普 ... -
hibernate入门(十一):级联操作inversin属性
2010-08-26 10:56 1510九、关联关系中的高级应用 1.级联操作: 在前面的一对多 ... -
hiberante入门(十):其它集合类型
2010-08-26 10:53 769八、其它集合类型 说明:在前面我们已经使用过set集合类型, ... -
hibernate入门(九):组件关系映射
2010-08-26 10:51 7785.组件关系映射: 典型实例:每个人有不同的名字,或者多个人 ... -
hibernate入门(八):多对多
2010-08-26 10:48 6484.多对多关系映射: 典型实例:一个学生可以有多个老师 ... -
hibernate入门(七):一对一
2010-08-26 10:42 7283.一对一关系映射: 典型的实例:一个人有一个身份证,而一个 ... -
hibernate入门(六):一对多
2010-08-26 10:36 6902.一对多关系映射: 上面提到的多个员工对应于一个部门,是多 ... -
hibernate入门(五):多对一
2010-08-26 10:32 6531.多对一关系映射: 一个部门有可以有多个员工,而一个员工只 ... -
hibernate入门(四):HQL QBC初步
2010-08-26 10:22 915四 完善工具类及HQL QBC ... -
hibernate入门(三):对象的三种状态
2010-08-26 10:20 690三 Session中的主要方法 ... -
hibernate入门(二):优化代码
2010-08-26 10:17 768二 优化代码 1.为会么要优化 在前面我们已经知道,获取S ... -
hibernate入门(一):第一个应用实例
2010-08-26 10:15 884一 第一个应用实例 1.搭建环境:新建一个名为Hiberna ...
相关推荐
在本篇博文中,我们将深入探讨Hibernate框架中的一个重要特性——一对一(One-to-One)关系映射。Hibernate作为Java领域中最流行的ORM(对象关系映射)工具,它允许开发者以面向对象的方式处理数据库操作,简化了...
NULL 博文链接:https://86asm.iteye.com/blog/493165
hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档
本文将结合"hibernate源码"和"hibernate配置"两个核心主题,深入探讨Hibernate的工作原理及配置细节,帮助读者从源码层面提升对Hibernate的理解。 一、Hibernate源码解析 1. 框架结构:Hibernate由多个模块组成,...
在Java的持久化框架中,Hibernate是一个非常流行的ORM(对象关系映射)工具,它允许开发者将数据库操作转化为对Java对象的操作。DAO(Data Access Object)层是软件设计模式中的一个重要概念,主要用于处理数据访问...
最新springboot2基础hiberante5完整项目,打包jar,运行jsp,包括后台与前台,拦截器,登录,后台下载就可以使用,注意不是jpa,里面有完整Dao,千万级数据项目分离的代码,为了适合老项目开发特意集成hiberante5....
1. 隐藏了数据库访问细节,提高了开发效率。 2. 提供了面向对象的查询语言HQL,使得查询更直观。 3. 支持级联操作,简化了对象关系的维护。 4. 内置缓存机制,提高性能。 5. 支持多种数据库,具有良好的移植性。 ...
开发工具:MyEclipse 6....Struts+Spring+Hiberante框架整合的简单登录系统 无需配置任何文件、只需在mysql中创建一个空数据库 如:create database test; 注:mysql数据库用户名:root 密码:root
Spring 框架是 Java 企业级应用开发中的核心组件,它提供了全面的软件基础设施,包括依赖注入(DI)、面向切面编程(AOP)以及众多的模块如数据访问、Web 应用、任务调度等。Spring MVC 是 Spring 框架的一部分,...
Hibernate Tools是一套全新而且完整的面向Hibernate3的工具集合,它包含了Eclipse插件和Ant编译流程。Hibernate Tools是JBoss Tools的核心组件,所以他也是JBoss Developer Studio的一部分
**hibernate5.0.7安装jar包详解** Hibernate是一个强大的Java持久化框架,它为开发者提供了在Java应用程序中管理关系数据库模型的工具。在5.0.7版本中,Hibernate引入了一系列改进和增强,使得它在处理数据库操作时...
hiberante4.2.3-part2
这适用于一些HQL无法处理或者效率更高的情况。你可以在Criteria查询中嵌入原生SQL,或者使用`Session.createSQLQuery()`来执行自定义的SQL。例如,获取所有用户的ID: ```java String sql = "SELECT id FROM User";...
Spring MVC 和 Hibernate 是两个在Java Web开发中广泛使用的框架,它们分别是用于构建MVC(Model-View-Controller)架构的Web应用和管理数据库操作的对象关系映射(ORM)工具。在实际项目中,这两个框架的集成能提供...
### Hibernate中的五大核心接口 #### 一、概述 在Hibernate框架中,存在五大核心接口,它们分别是:`Session`、`SessionFactory`、`Transaction`、`Query` 和 `Configuration`。这些接口对于Hibernate的正常运行至...
标题“Hiberante3相关文档”表明了主要讨论的是关于Hibernate3这一持久化框架的资料集合,可能涵盖了多个方面,如查询语言、缓存机制以及数据加载策略。 描述中的“Hiberante3_HQL”提示我们将会涉及到Hibernate...
hiberante-4.2.3-part3
hiberante-4.2.3-part4
hiberante3.2纯静源码
hiberante 代码save方法过程,分析