基于iBatis的通用持久层对象.docx

上传人:b****3 文档编号:12661514 上传时间:2023-04-21 格式:DOCX 页数:8 大小:20.86KB
下载 相关 举报
基于iBatis的通用持久层对象.docx_第1页
第1页 / 共8页
基于iBatis的通用持久层对象.docx_第2页
第2页 / 共8页
基于iBatis的通用持久层对象.docx_第3页
第3页 / 共8页
基于iBatis的通用持久层对象.docx_第4页
第4页 / 共8页
基于iBatis的通用持久层对象.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

基于iBatis的通用持久层对象.docx

《基于iBatis的通用持久层对象.docx》由会员分享,可在线阅读,更多相关《基于iBatis的通用持久层对象.docx(8页珍藏版)》请在冰豆网上搜索。

基于iBatis的通用持久层对象.docx

基于iBatis的通用持久层对象

ibatis介绍

  使用ibatis提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate实现ORM而言基本一致,而对于具体的数据操作,Hibernate会自动生成SQL语句,而ibatis则要求开发者编写具体的SQL语句。

相对Hibernate等“全自动”ORM机制而言,ibatis以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。

作为“全自动”ORM实现的一种有益补充,ibatis的出现显得别具意义。

  版权声明:

任何获得Matrix授权的网站,转载时请务必保留以下作者信息和链接

  作者:

fellowArrayArray

  原文:

  关键字:

iBatis;ORM

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

  在大多数时候,我们所需要的持久层对象(PO)大多都是一张表(or视图)对应一个类。

按照Hibernate的思想,就是抛开数据库的束缚,把焦点集中到业务对象中。

而很多自动化工具的确让做到了通过表结构生成对应的对象,or通过对象自动生成表。

对于小项目来说,一切都是简单的;对于有规范设计的项目来说,PO的设计也不是一件困难的工作。

但是对于那些业务变动频繁的项目来说,改动PO可能成了一件很繁重的工作。

试想一下,假设某个表需要增加一个字段:

对于Hibernate(oriBaits),首先要改配置文件,然后PO,然后DAO(也许没有),然后业务逻辑,然后JO,然后界面,etc,贯通了全部层次。

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

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

  二、基于什么技术

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

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

  

  其中圈圈1、2、3描述了iBatis最重要的三个对象。

  圈圈1:

statement简单来说就是存储sql语句的配置信息,一个最简单的statement:

  

    insertintoPRODUCT(PRD_ID,PRD_DESCRIPTION)values(1,“ShihTzu”)    

  其中id属性是这个statement的唯一标识,全局不能重复。

  以上当然是最简单的了,没有参数也不需要返回值,但实际情况下基本都需要传入参数,下面就是介绍参数。

  圈圈2:

参数对象主要分两种类型:

parameterMap、parameterClass和InlineParameter。

  其中parameterMap是配置文件定义传入参数表,如下:

  

        insertintoPRODUCT(PRD_ID,PRD_DESCRIPTION)values(?

?

);    

  而parameterClass是传入参数对象(JavaBean),如下:

  

    insertintoPRODUCTvalues(#id#,#description#,#price#)    

  InlineParameter则是强化版的parameterClass,如下:

  

    insertintoPRODUCT(PRD_ID,PRD_DESCRIPTION)  values(#id:

NUMERIC:

-ArrayArrayArrayArrayArrayArray#,#description:

VARCHAR:

NO_ENTRY#);    

  其中第一种方法看着就复杂,实际是为了兼容老版本留下来的,所以parameterClass是我们最常用的方法。

官方文档对parameterClass介绍很详细,因为这是核心之一,具体请自己查阅。

有3个特性说明一下:

  a.parameterClass对象可以传入一个Map对象(orMap子类)。

本来如果是传入JavaBean,程序会通过get/set来分析取得参数;而Map是key-value结构的,那程序会直接通过key来分析取参数。

  b.看以下语句:

  

    insertintoPRODUCTvalues(#id#,#description#,#price#,#classify.id#)    

  蓝色部分#classify.id#翻译过来实际是product.getClassify().getId(),classify是Product对象的一个子对象。

  c.在模板sql语句中除了“#”以外,还有“$”,它们两代表的意思当然不同了:

  

    select*fromPRODUCTorderby$preferredOrder$    

  “#”在生成sql语句的过程中,会变成“?

”,同时在参数表中增加一个参数;

  “$”则会直接替换成参数对象对应的值,例如上面的preferredOrder的值可能是“price”,则生成的sql语句就是:

select*fromPRODUCTorderbyprice。

  *需要特别说明的是传入参数这一部分将会是后面正题“通用持久层对象”的核心,怎么个通用法,怎么设计模板sql语句,都是在这部分上。

  圈圈3:

结果对象跟参数对象差不多,也有两种,resultMap和resultClass,如下:

  resultMap就是配置文件中预定义了要取得的字段:

  

            select*fromPRODUCT    

  resultClass则是通过分析返回的字段,来填充结果对象:

  

    SELECTPER_IDasid,PER_FIRST_NAMEasfirstName  FROMPERSONWHEREPER_ID=#value#    

  跟参数对象相反,结果对象一般使用resultMap形式。

引用官方的话:

使用resultClass的自动映射存在一些限制,无法指定输出字段的数据类型(如果需要的话),无法自动装入相关的数据(复杂属性),并且因为需要ResultSetMetaData的信息,会对性能有轻微的不利影响。

但使用resultMap,这些限制都可以很容易解决。

  三、正题来了,怎么做“通用持久层对象”

  1.表结构:

  每个表都必须包含两个字段:

id和parentId,其他字段按照需求来定义,其他各种索引、约束、关系之类的也按需求定义。

  2.通用的持久层对象,CustomPO:

  

  publicclassCustomPO{  protectedStringmoduleTable;//该PO对应的表名(视图名)  protectedintid;//表的id  protectedintparentID;//父表的id(如果有的话)  protectedMapfieldMap;//字段Map,核心,用于存储字段及其值  publicStringgetModuleTable()  publicvoidsetModuleTable(StringmoduleTable)  publicintgetId()  publicvoidsetId(intid)  publicintgetParentID()  publicvoidsetParentID(intparentID)  publicMapgetFieldMap()  publicvoidsetFieldMap(MapfieldMap)  publicvoidcopyFieldMap(MapfieldMap)  //取得字段名列表  publicListgetFieldList()  //设置字段名列表。

如果fieldMap没有相应的字段,则增加,字段值为null;如果有则不增加。

  publicvoidsetFieldList(ListfieldList)  //返回字段的“字段名-字段值”列表,使用com.fellow.pub.util.KeyValuePair对象作为存储  publicListgetFieldValueList()  }  

  那些成员变量的get/set就没什么说的,主要说说getFieldValueList()这个方法。

该方法返回一个列表,列表元素是一个key-value结构,简单来说就是把字段map序列化。

在构造模板sql语句时会体现它的用途。

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

  

          SELECTid,parentID$fieldList[]$FROM$moduleTable$WHEREid=#id#      INSERTINTO$moduleTable$(parentID    $fieldValueList[].key$    )  VALUES(#parentID#    #fieldValueList[].value#    )    SELECTlast_insert_id()          UPDATE$moduleTable$SET    $fieldValueList[].key$=#fieldValueList[].value#    WHEREid=#id#        DELETEFROM$moduleTable$WHEREid=#id#    

  要注意的地方如下:

  a.跟一般的ibatis配置文件不一样,该配置中没有包含resultMap,使用的就是resultClass的方式(效率没那么高的那种)。

当然,也可以使用resultMap,这样就要为每个表写自己的配置文件了。

因此,在该设计没完成前,我暂时先使用resultClass的方式。

  b.上面只列举了最简单的增删改以及按id查询,并没有更复杂的查询,为什么呢?

因为我还在研究中。

研究通用的模板sql的写法。

  4.CustomPO对应的DAO:

  我使用了ibaits提供的DAO框架,很好用,不单支持ibatis的框架,还支持Hibernate、JDBC等等,而且是与ibatis本身独立的,完全可以单独使用。

以后就不用自己写DAO框架了。

一下是该DAO接口:

  

  publicinterfaceICustomDAO{  /**  *通过传入moduleTable和id取得一条记录  */  CustomPOfindByID(StringmoduleTable,intid)throwsException;  /**  *通过传入CustomPO对象取得一条记录  *@parampoCustomPO该对象在传入前应该先设置moduleTable和id参数,  *并且使用setFieldList()函数设置字段列表(该设置决定所返回的字段)。

  */  CustomPOfindByID(CustomPOpo)throwsException;  /**  *通过传入moduleTable和parentID取得一条记录  */  CustomPOfindByParentID(StringmoduleTable,intparentID)throwsException;  /**  *通过传入CustomPO对象插入一条记录  *@parampoCustomPO该对象在传入前应该先设置moduleTable和id参数,  *并且使用setFieldMap()函数设置“字段-值”对。

  */  voidinsert(CustomPOpo)throwsException;  /**  *通过传入CustomPO对象更新一条记录  *@parampoCustomPO该对象在传入前应该先设置moduleTable和id参数,  *并且使用setFieldMap()函数设置“字段-值”对。

  */  voidupdate(CustomPOpo)throwsException;  /**  *删除moduleTable和id所对应的记录  */  voiddelete(StringmoduleTable,intid)throwsException;  }  

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

  另外列几个实现的片断:

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

  

  protectedvoidfill(Mapresult,CustomPOpo){  LongreturnId=(Long)result.get("id");  LongreturnParentID=(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()函数

  

  //查询  Mapresult=(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了。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1