您当前位置:设计在线网 >> JavaScript >> 浏览文章

iBatis介绍 基于iBatis的通用持久层对象

分享到:
本文章讲述了iBatis介绍 基于iBatis的通用持久层对象.

iBatis介

使用iBatis提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate实现ORM 而言基本一致,而对于具体的数据操作,Hibernate会自动生成SQL语句,而iBatis则要求开发者编写具体的SQL语句。相对Hibernate等“全自动”ORM机制而言,iBatis以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,iBatis的出现显得别具意义。

一、为什么要设计“通用”的东西

在大多数时候,我们所需要的持久层对象(PO)大多都是一张表(or视图)对应一个类。按照Hibernate的思想,就是抛开数据库的束缚,把焦点集中到业务对象中。而很多自动化工具的确做到了通过表结构生成对应的对象,or通过对象自动生成表。对于小项目来说,一切都是简单的;对于有规范设计的项目来说,PO的设计也不是一件困难的工作。但是对于那些业务变动频繁的项目来说,改动PO可能成了一件很繁重的工作。试想一下,假设某个表需要增加一个字段:对于Hibernate(or iBaits),首先要改配置文件,然后PO,然后DAO(也许没有),然后业务逻辑,然后JO,然后界面,etc,贯通了全部层次。

恩,写程序的都不喜欢这些重复劳动,但是做企业级应用的谁不是每天在这些工作中打滚。

研究过iBaits以后,发现有些通用的方法可以解决,就是设计一个通用的持久层对象。

二、基于什么技术

iBatis可以使用Map对象作为PO,Hibernate好像也有相关的功能(我没有细看,不确定)。

iBatis执行一条指令的过程大概是这样的:

点击浏览下一页public List getFieldValueList()

}

那些成员变量的get/set就没什么说的,主要说说getFieldValueList()这个方法。该方法返回一个列表,列表元素是一个key-value结构,简单来说就是把字段map序列化。在构造模板sql语句时会体现它的用途。

3、iBatis对象配置文件CustomPO.xml

parameterClass="customPO">

SELECT id, parentID

$fieldList[]$

FROM $moduleTable$ WHERE id = #id#

INSERT INTO $moduleTable$ (parentID

$fieldValueList[].key$

)

VALUES (#parentID#

#fieldValueList[].value#

)

SELECT last_insert_id()

UPDATE $moduleTable$ SET

$fieldValueList[].key$ = #fieldValueList[].value#

WHERE id = #id#

DELETE FROM $moduleTable$ WHERE id = #id#

#p#

要注意的地方如下:

a、跟一般的iBatis配置文件不一样,该配置中没有包含resultMap,使用的就是resultClass的方式(效率没那么高的那种)。当然,也可以使用resultMap,这样就要为每个表写自己的配置文件了。因此,在该设计没完成前,我暂时先使用resultClass的方式。

b、上面只列举了最简单的增删改以及按id查询,并没有更复杂的查询,为什么呢?因为我还在研究中。。。研究通用的模板sql的写法。

4、CustomPO对应的DAO

我使用了ibaits提供的DAO框架,很好用,不单支持iBatis的框架,还支持Hibernate、JDBC等等,而且是与iBatis本身独立的,完全可以单独使用。以后就不用自己写DAO框架了。该DAO接口是:

public interface ICustomDAO {

/**

* 通过传入moduleTable和id取得一条记录

*/

CustomPO findByID(String moduleTable, int id) throws Exception;

/**

* 通过传入CustomPO对象取得一条记录

* @param po CustomPO 该对象在传入前应该先设置moduleTable和id参数,

* 并且使用setFieldList()函数设置字段列表(该设置决定所返回的字段)。

*/

CustomPO findByID(CustomPO po) throws Exception;

/**

* 通过传入moduleTable和parentID取得一条记录

*/

CustomPO findByParentID(String moduleTable, int parentID) throws Exception;

/**

* 通过传入CustomPO对象插入一条记录

* @param po CustomPO 该对象在传入前应该先设置moduleTable和id参数,

* 并且使用setFieldMap()函数设置“字段-值”对。

*/

void insert(CustomPO po) throws Exception;

/**

* 通过传入CustomPO对象更新一条记录

* @param po CustomPO 该对象在传入前应该先设置moduleTable和id参数,

* 并且使用setFieldMap()函数设置“字段-值”对。

*/

void update(CustomPO po) throws Exception;

/**

* 删除moduleTable和id所对应的记录

*/

void delete(String moduleTable, int id) throws Exception;

}

我没有把所有的方法都列出来,反正挺简单的,跟一般的DAO没什么分别。

另外列几个实现的片断:

a、统一的数据装填函数,需要手工把id和parentID字段去掉。

protected void fill(Map result, CustomPO po) {

Long returnId = (Long) result.get("id");

Long returnParentID = (Long) result.get("parentID");

result.remove("id");

result.remove("parentID");

if (returnId != null) po.setId(returnId.intValue());

if (returnParentID != null) po.setParentID(returnParentID.intValue());

po.setFieldMap(result);

}

b、一般的查询,返回的是一个map,然后再用fill()函数。

//查询

Map result = (Map)this.queryForObject("customPO_findByID", po);

//处理返回结果

if(result == null)

po = null;

else

fill(result, po);

c、增删改,没有返回值,值得一提的是增加操作完成后,po里面的id会更新,具体看前面相关的statement。

//增删改

this.insert("customPO_insert", po);

this.update("customPO_update", po);

this.delete("customPO_delete", po);

5、前面是通用的部分,光是通用是不够的。因此我另外建立了一套配置文件,记录字段对应关系。看看我所定义的一个配置文件,挺简单的:

其中,name是字段名,column是字段对应数据表的字段名,type是字段类型,not-null是是否不能为空,unique是是否唯一。只有name这个属性是必填的,column如果不填默认与name相等,type默认为string,not-null和unique默认为false。

配置文件的读取类在这里就省略了。

为什么要自己定义一套这个框架?好像挺多此一举的,但是没办法,iBatis配置文件的信息是封闭的,我无法取得。另外我考虑的是:

a、viewer层

在web开发中,我可以在这套配置框架的基础上,建立自己的标签,实现数据自动绑定的功能;GUI开发中也可以做相应的功能。

b、module层

可以做通用的业务操作,不需要为每个业务都都做独立的业务逻辑。

四、有什么优点、缺陷

1、优点

a、“通用”,一切都是为了通用,为了减少重复劳动,一个个项目面对不同的业务,其实说到底都是那些操作。各种持久成框架已经带给我们不少的方便,但是在实际业务逻辑的处理上好像还没有一个这样的框架。

b、极大地减少代码量。前面说了,数据库改一个字段,PO、DAO、module、JO、viewer、validator全都要改一遍。使用了这套东西,可以把绝大部分的劳动都放在配置文件和UI上。当然,这是完美的设想,对于很多情况,业务逻辑还是要手工写的。

c、好像没有c了。

2、缺点

a、通常通用的东西都缺乏灵活性,在我的实际应用中也发现了这样那样的问题,解决方法都是以通用为基本原则。但是如果针对的是某个项目,那就可以针对业务来修改了。

b、性能问题。因为使用resultClass,按照文档所说的,性能没有resultMap好。当然也可以使用resultMap,如前所说,就要对每个PO写配置文件了,工作量也不少。

c、也好像没有c了。

五、后话

我总是喜欢写一些通用的东西,总是想把它设计成万能的。但是经过多次失败总结出来,我发现通用的东西在很多情况下都等于不能用。但我就是喜欢往通用方面想,这个毛病不知道什么时候才能改得了。其实在Delphi平台中,我早就实现了相关的东西,但是用delphi总是限制于ADO+Data Module这样掉牙的模式。现在转向java,发现有iBatis、hibernate这么多好的持久层框架,自然有移植必要了。

推荐阅读:
基于Hibernate校验器组件实现Web开发中的校验逻辑讲解
《Java应该这么学》书本内容概要
使用java采用SSH或SFTP方式连接远程服务器

相关文章:

推荐文章  
赞助商链接  
热门排行  
主题推广  
中国设计在线网 All Rights Reserved. 互联网违法和不良信息举报
信息产业部备案号:湘ICP备09001063号