转载自: http://blog.csdn.net/yejun8214/archive/2007/10/22/1838016.aspx
为书写方便,本文采用如下简写约定:
Transaction:Tx
Manager:Mgr
Context:Ctx
Interface:Iface
iBATIS DAO框架如图:
DAO的核心在于DaoManager,DaoManager的创建代码如下:
Reader reader = Resources.getResourceAsReader("dao.xml");
DaoManager daoMngr = DaoManagerBuilder.buildDaoManager(reader);
DaoManager
是接口,查看
DaoManagerBuilder
源代码可发现,其
buildDaoManager
方法返回的是一个
StandardDaoManager
实例。
buildDaoManager
方法调用了XmlDaoManagerBuilder类的buildDaoManager方法,该方法完成如下工作:
1. 创建一个
StandardDaoManager
实例
stdDaoMgr
;
2.
创建一个用于全局收集各种
property
(来自
<properties>
元素指向的资源文件或来自当前
dao.xml
中的各级
<property>
元素)的
Properties
对象
;
3.
解析
dao.xml
文件(建议阅读本文时参考一份dao.xml文件,如JGameStore应用中给出的dao.xml)中的
<properties>
元素,将相应
property
加入;
4.
解析
dao.xml
文件中的
<context>
元素,得到一个
DaoContext
实例
daoCtx
(
4.1
);并将调用
stdDaoMgr.addContext
方法将
daoCtx
添加到
stdDaoMgr
中(
4.2
):
4.1
解析
dao.xml
文件的
<context>
元素得到
daoCtx
的过程为:
实例化一个
DaoContext
对象
daoCtx
;
将其
daoManager
字段设为我们的
stdDaoMgr
;
如
<context>
有
id
属性,则将
daoCtx
的
id
字段取为此属性的值;
解析
<context>
的子元素:
4.1.1
解析
<txMgr>
子元素,得到
DaoTxMgr
接口实例
txMgr
,设为
daoCtx
的相应字段,解析过程为:
根据
<txMgr>
子元素的
type
属性,实例化一个相应的
DaoTxMgr
实例
txMgr
;
解析
<txMgr>
的
<property>
子元素,将所得
property
添加入
properties
;
根据
properties
对
txMgr
进行配置(即调用
txMgr.configure
方法);
4.1.2
解析
<dao>
子元素,得到一个
DaoImpl
类实例
daoImpl
,然后将其加入
daoCtx
;
4.1.2
.1
解析过程为:
4.1.2
.1.1
实例化一个
DaoImpl
类实例
daoImpl
;
4.1.2
.1.2
将
daoImpl
的
daoMgr
字段设为我们的
stdDaoMgr
;
4.1.2
.1.3
将
daoImpl
的
daoCtx
字段设为我们的
daoCtx
;
4.1.2
.1.4
将
daoImpl
的
daoIface
字段设为
<dao>
的
iface
属性值对应的
class
;
4.1.2
.1.5
将
daoImpl
的
daoImplementation
字段设为
<dao>
的
implementation
属性值对应的
class
;
4.1.2
.1.6
根据
implementation
属性实例化一个
DAO
实现类,设为
daoInstance
字段值,注意,该实例一定是一个
Dao
接口实例,因为任何一个都继承自
DaoTemplate
,而
DaoTemplate
实现了
Dao
接口;
4.1.2
.1.7
创建一个当前
DAO
实现类的代理,设为
daoImpl
的
proxy
字段值,该代理在启用显式事务时会在调用委托方法前调用
daoCtx.startTx
方法;在使用隐式事务时则在调用委托方法的前后分别调用
daoCtx.startTx
方法和
commitTx
方法(在
finally
块中还调用
daoCtx.endTx
方法)。
4.1.2
.2
将
daoImpl
加入
daoCtx
的过程为:以当前
daoImpl
填充一张从
daoIface
到
DaoImpl
实例的表;
4.2
调用
stdDaoMgr.addContext
方法将
daoCtx
添加到
stdDaoMgr
中的过程为:
4.2.1
以当前
daoCtx
填充一张由
id
到
DaoCtx
实例的表;
4.2.2遍历
daoCtx
中存放的所有
daoImpl
,填充一张从
daoIface
到
daoCtx
的表和一张从
Dao
接口实例(即
daoImpl
中的
proxy
和
daoInstance
)到
daoCtx
的表;
5.
客户以某
DaoIface
调用
DaoMgr.getDao
方法得到一个
DaoIface
实现类实例
xxxYyyDao
的过程为:
stdDaoMgr查找其
从
daoIface
到
daoCtx
的表,得到当前
daoIface
所在
daoCtx
,然后调用
daoCtx.getDao
方法:
daoCtx
查找其从
daoIface
到
DaoImpl
实例的表,得到
daoImpl
,返回其
proxy
字段;
6.
隐式事务:
隐式事务中,客户每调用一个
xxxYyyDao
中方法时,都是一次完整的事务,因为
xxxYyyDao
是调用
DaoMgr.getDao
方法得到的,而根据
5
,其实
xxxYyyDao
是一个代理,又根据
4.1.2
.1.7
,该代理会“在调用其委托方法前后分别调用
daoCtx.startTx
方法和
commitTx
方法(在
finally
块中还调用
daoCtx.endTx
方法)”。
6.1 daoCtx.startTx
方法调用其
txMgr
字段的
txMgr.startTx
方法,该方法返回一个
DaoTx
实例
daoTx
,
daoCtx
将它放入一个线程变量中;
6.2 DaoIface
实现类中,由于其一定继承自某个
DaoTemplate
,以调用其中的数据库访问方法,而这些数据库访问方法都会以自己作为参数调用
daoMgr
的
getTx
方法;该方法查找
4.2.2
中提到的从
Dao
接口实例到
daoCtx
的表,得到一个
daoCtx
,然后调用
daoCtx.getTx
;
daoCtx.getTx
将存储在线程变量中的
daoTx
实例返回;
6.3 daoTx
实例包含数据库操作所需的关键元素,例如对于
SqlMapDaoTx
,其中就包含一个
SqlMapClient
实例,
SqlMapDaoTemplate
中的数据库访问方法(如
insert
,
queryForList
等)都是先调用
daoMgr.getTx
,得到
daoTx
实例,将其强制转化为
SqlMapDaoTx
实例,然后调用其
getSqlMap
方法得到
SqlMapClient
实例,再调用
SqlMapClient
实例中的相应方法;又如对于
JDBC
的情况,对应
DaoTx
为
ConnectionDaoTx
,该类包含一个,每次调用
JdbcDaoTemplate
方法的
getConnection
方法时,该方法都先调用
daoMgr.getTx
,得到
daoTx
实例,将其强制转化为
ConnectionDaoTx
实例,然后调用其
getConnection
方法得到其中的
Connection
实例,然后调用其中的相应方法。
6.4 daoCtx.commitTx
方法调用其
txMgr
字段的
txMgr.commitTx(daoTx)
方法完成事务的提交。
6.5 daoCtx.endTx
方法调用其
txMgr
字段的
txMgr.endTx(daoTx)
方法结束事务。
7.
显式事务:
显式事务通常包括三个步骤:首先,调用
daoMgr.startTx
,然后调用
xxxYyyDao
中的方法,最后调用
daoMgr.commitTx
。
7.1 daoMgr.startTx
的工作非常简单,只是设置
stdDaoMgr
中标记显式事务的字段;
7.2
调用
xxxYyyDao
中的方法时,由于代理,将先调用
daoCtx.startTx
,此过程同
6.1
;
7.3
调用
daoMgr.commitTx
时,该方法最终调用的也是
daoCtx.commitTx
,请参考
6.4
下面以一个问题的实现来完成本文的总结工作:如果要由我来实现iBATIS的DAO框架对于Hibernate的支持,我们应该如何实现?
Hibernate的核心在于Session,所有的数据库操作都可调用Session上的相应方法完成,所有考虑用于支持Hibernate的DaoTx实现应该是对Session的一个包装,该实现中有一个返回当前Session的getSession方法(当然也包括提交和回滚方法)。同样的,DaoTxMgr实现类的configure方法负责完成某个Session实例(session)的配置,startTx方法负责返回一个包装了当前session实例的DaoTx实例,commitTx方法将传入的daoTx实例强制转化后调用daoTx上的commit方法,rollbackTx方法将传入的daoTx实例强制转化后调用daoTx上的rollback方法。而HibernateDaoTemplate类的关键就在于其protected的getSession方法,该方法先调用daoMgr.getTx得到当前daoTx实例,强制转化后调用daoTx上的getSession方法即可。