扩展 iBatis 以透明支持多种数据库.docx

上传人:夺命阿水 文档编号:94089 上传时间:2022-12-11 格式:DOCX 页数:8 大小:26.53KB
返回 下载 相关 举报
扩展 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(8页珍藏版)》请在课桌文档上搜索。

1、扩展iBatis以透亮支持多种数据库iBatis是一个开源的对象关系映射框架,着重于POJO与SQL之间的映射关系。和其它ORM框架不同,iBatis开发者需要自己编写利维护SQL语句。为了得到更好的执行性能,在实际开发中免不了会使用一些数据库方言。随之而来的一个问题是,如何在增加对新的数据库支持的同时尽可能避开对已有应用程序代码的修改?本文供应了一个简洁有效的方法,通过扩展iBatis来透亮地支持多数据库方言。iBatis简介iBatis是一个开源的对象关系映射程序,着重于POJO与SQL之间的映射关系。使用时,开发者供应一个被称为SQL映射的XML文件,定义程序对象与SQL语句间的映射关系

2、,iBatis会依据SQL映射文件的定义,运行时自动完成SQL调用参数的绑定以及JDBCResuItSet到JaVaPoJO之间的转换。下面是一个简洁的例子,相比其它ORM工具,iBatis相对简洁,更简洁上手。清单1.POJO对象publicclassBIogDataimplementsSerializableprotectedStringid;protectedStringname;protectedintrating=0;publicStringgetld()returnid;1publicStringgetName()returnname;(publicintgetRating()re

3、turnrating;1publicvoidsetId(Stringid)this.id=id;)publicvoidsetName(Stringname)this.name=name;1publicvoidsetRating(intrating)this.rating=rating;清单2.SQL映射文件Sqlmarxmlinsertintoblogs(id,name,rating)values(#id#,#name#,#rating#)updateblogssetname=#name#,rating=#rating#whereid=#id#deletefromblogswhereid=#i

4、d#select*fromblogsorderbyratingdescfetchfirst$SiZe$rowsonly清单3.iBatis配置文件SQLMAPCONFIGXML/SQL映射声明清单4.SQL访问示例Stringcfg=,SQLMAPCONFIGXML;Readerr=Resources.getResourceAsReader(cfg);SqlMapClientclient=newSqlMapConfigParser().parse(r);/插入BlogDatao=newBlogData();o.setld(id,r);o.setName(test);client.insert(

5、SAVEBLOG,o);/更新o.setRating(10);Client.UpdateCUPDATEBLOG,o);/删除client.delete(REMOVEBLOG,id);/查询Mapparams=newHashMapO;params.put(size,5);Listl=client.queryForList(GETMOSTPOPULARBLOGparams,0,5);iBatis应用中的多数据库支持在iBatis应用中,开发者仍需自己编写详细的SQL语句,iBatis只是隐蔽和简化了JDBC的相关调用。实际开发中,我们不免需要就SQL语句针对各种特定的数据库进行特别优化,以期猎取更

6、好的执行性能,随之而来的一个问题是,如何应对新的数据库平台支持的需求。一般的做法是,修改SQL映射文件,供应一些新的针对新数据库平台的SQL语句版本,然后修改程序代码,添加相应调用。连续上面的例子。上面的例子中,对于SQL语句Getmostpopularblog的定义,我们使用了db2特有的sql方言“fetchfirstnROWS0NLY,对于这样的程序,假如盼望增加对MYSQL的支持,依据一般的做法,需要:1 .修改Sqlmarxml,增力口语句定义getmostpopularblog_mysql”。清单5.增加语句定义select*fromblogsorderbyratingdescfe

7、tchfirst$size$rowsonlyselect*fromblogsorderbyratingdesclimit0,$size$2 .搜寻程序代码,在每一个调用iBatis“GETMOSTPOPULARBLOG”的地方,增加检测MYSQL数据库引擎的代码,并添加对“GETMOSTPOPULARBLOG_MYSQL”的iBatis调用。清单6.增加检测数据库引擎的代码SqIMapClientclient=/查询Mapparams=newHashMapO;params.put(size,5);List1=null;Connectionconn=client.getCurrentConnec

8、tion();StringprodName=conn.getMetaData().getDatabaseProductName().toLowerCase();if(prodName.indexOf(mysql)-1)(/MicrosoftSQLServer1=client.queryForListCETMOSTPOPULARBLOG-MYSQL,params);)else1=client.queryForList(,GETMOSTPOPULARBLOG,params);每增加一个新的数据库支持,增加了一些新的针对新数据库平台的SQL语句版本,我们就不得不搜寻源代码,找出全部受到影响的iBat

9、is调用,修改并增加针对新数据库的特别调用。代码维护时,每次涉及使用数据库方言的SQL语句,我们也都必需记住当心谨慎地处理全部相关的数据库特化调用。这样的工作乏味且简洁出错。本文,我们试图在分析iBatis源码的基础上,通过适当扩展iBatis,供应一个高效便利的解决方案。扩展SqlMapConfigParser在iBatis应用中,SqlMapConfigParser负责解析iBatis配置文件,加载全部的SQL映射文件,生成SqIM叩Cliem实例,这是长久化调用的入口。SqIM叩COnfigParSer的实现并不简单。成员函数ParSer将传入的配置文件XML输入流交给一个XML解析器。

10、XML解析器解析XML输入,并针对每一个XMLFragmem调用合适的处理器处理。全部的处理器都在SqlMapConfigParser类实例初始化时预先被注册到XML解析器上,其中,对于iBatis配置中的SQL映射声明,只是简洁地调用类SqIM叩ParSer中的parser方法,解析并加载相应的SQL映射定义文件。清单7.SqlMapConfigParser实现publicclassSqIMapConfigParser/XML解析器protectedfinalNodeletParserparser=newNodeletParserO;publicSqlMapConfigParserO/注册X

11、ML处理器addSqlMapNodelets();/more(publicSqIMapClientparse(Readerreader)/调用XML解析器解析传入的配置文件XML输入流parser,parse(reader);returnvars.client;1protectedvoidaddSqlMapNodelets()/XML处理器,处理XPalhSqIMaPConfigsqlM叩”,即SQL映射声明parser.addNodelet(sqlMapConfigsqlMapnewNodelet()publicvoidprocess(Nodenode)throwsException(Pro

12、pertiesattributes=NodeletUtils.parseAttributes(node);Stringresource=attributes.getProperty(,resource);Readerreader=Resources.getResourceAsReader(resource);newSqlMapParser(vars).parse(reader);/调用SqlMapParseEparser方法/解析并加载SQL映射文件);我们继承iBatis原有的配置文件解析器实现SqlM叩COnfigParser,重写其中对SQL映射声明的处理。首先,我们重写SqIMapCo

13、nfigParser的成员函数addSq)MapNodelets对于从XML解析器传入的SQL映射声明节点,我们并不马上进行解析处理,而只是将它们纪录下来。清单8.重写addSqlMapNodclcts方法publicclassSqlMapConfigParserExextendsSq1MapConfigParser(ListSqlMapNodeList=newArrayList();protectedvoidaddSqlMapNodelets()/XML处理器,处理XPath:/SqIMaPCOnfigsqlMap”,即SQL映射声明parser.addNodelet(sqlMapConfi

14、gsqlMap,newNodelet()publicvoidprocess(Nodenode)throwsExceptionsqlMapNodeList.addNode(node););这些SQL映射声明被放到最终处理,此时SqlMapClient实例已经基本构造完毕,至少,我们可以平安地调用它的相关方法,打开数据库连接,查询数据库引擎相关信息。对于每个SQL映射声明,SqIMapConfigParSerEX调用其成员函数方法handleSqlMapNode进行相应的SQL映射文件解析和加载处理,数据库引擎支持的SQL方言版本信息作为参数被一并传入。清单9.重写parse方法publicint

15、erfaceDialectMapping(publicStringgetDialect(StringproductName);/返回数据库平台支持的SQL方言信息)publicclassSqlMapConfigParserExextendsSqlMapConfigParser(ListSqlMapNodeList=newArrayList();DiaIectMappingdialectMapping=publicSqIMapClientparse(Readerreader)super,parse(reader);StringSqlDialect=null;SqIMapCIientclient=

16、vars.client;Connectionconn=client.getDataSource().getConnection();DatabaseMetaDatadbMetaData=conn.getMetaData();StringproductName=dbMetaData.getDatabaseProductName();SqlDialect=dialectMapping.getDialect(productName);conn.close();for(Iteratoriter=sqlMapNodeList.iterator();iter.hasNext();)(hand1eSqlMa

17、pNode(Node)iter.next(),sqlDialect);)returnclient;对于传入的SQL映射声明,除了解析并加载SQL映射声明中指定的SQL映射文件,IiandleSqlM叩NOde还依据传入的SQL方言版本信息,以肯定的路径规章,查找针对该SQL方言的SQL映射文件定制版木,将它们一并解析加载。清单10.HandlcSqlMapNode方法publicinterfaceSqIMapStreamMergerpublicvoidaddInput(InputStreaminput);publicInputStreammerge();publicclassSqlMapCon

18、figParserExextendsSq1MapConfigParser(SqIMapStreamMergerSqIMapStreamMerger=publicvoidhandleSqlMapNode(Nodenode.StringSqlDialect)Propertiesattributes=NodeletUtils.parseAttributes(node);Stringresource=attributes.getProperty(resource);/读取SQL映射声明指定的SQL映射文件InputStreamis=Resources.getResourceAsStream(resou

19、rce);sqlMapStreamMerger.addlnput(is);/查找并试图读取针对SQL方言SqlDialect的SQL映射文件定制版本intidx=resource.lastlndexf(7,);resource=resource.substring(0,idx)+SqlDiaIect+resource.substring(idx);is=Resources.getResourceAsStream(resource);if(is!=null)sqlMapStreamMerger.addInput(is);/将读取到的SQL映射文件,包括基本的SQL映射文件,以及为特定数据库的定制

20、版本,/合成一个SQL映射文件XML数据流交给SqlM叩ParSer解析处理Readerreader=newInputStreamReader(SqlMapStreamMergenmergeO);newSqlMapParser(vars).parse(reader);成员函数handleSqlMapNode将找到的SQL映射文件,包括SQL映射声明中指定的基本的SQL映射文件,以及以肯定路径规章找到的针对特定数据库的SQL映射文件定制版本,通过SqlMapStreamMerge对象整合成一个SQL映射文件,才递交给SqlMapParser解析处理。SqlMapStreamMerge确保:1 .

21、结果SQL映射文件中不存在重复ID的SQL映射配置块(SwemenI、insertupdatedeletesqkresultMap等)。假如基本的SQL映射文件与针对特定数据库的SQL映射文件定制版本之间存在重复ID的SQL映射配置块定义,SqlMapStreamMerge保留后者掩盖前者;2 .结果SQL映射文件中的配置块按引用依靠挨次有序排列。即全部的resullM叩声明都位于引用它们的statement声明之前,被继承的resultM叩声明都位于继承的resultMap声明之前等。先Merge再解析,这是必要的,由于SqIM叩ParSer本身并不支持SQL映射定义的方法重写。使用使用扩展

22、的SqlMapConfigParser实现SqlMapConfigParserEx,可以大大简化应用程序中多数据库支持问题的解决。还是之前那个例子。首先,我们使用SqlMapConfigParserEx替换程序中的SqlMapConfigParser使用。清单11.在应用代码中使用扩展的SqlMapConfigParserExStringcfg=,SQLMAPCONFIGXML;Readerr=Resources.getResourceAsReader(cfg);/oldcode/SqlMapCIientclient=newSqlMapConfigParser().parse(r);/newc

23、odeSqIMapCIientclient=newSqlMapConfigParserEx().parse(r);现在,要增加对MySQL的支持,只需建立一个新的SQL映射文件mysqlSQLMAP.XML,重写Sqlmarxml中Getmostpopularblog的sql定义。JaVa代码可以连续保持数据库平台透亮性,无需作出任何修改。清单12.针对MySQL的配置文件mysqlSQLMAP.XMLselect*fromblogsorderbyratingdesclimit0,$size$运行时,SqlMapConfigParserEx会自动检测数据库引擎版本信息,读取文件ZmysqlZS

24、QLMARXML,使用其中的(针对MYSQL定制的)GETMOSTPOPULARBLOG定义掩盖Sqlmarxml中的DB2方言版本,从而确保程序行为的正确性。我们支持,针对新的数据库平台,对SQL映射文件中的任意配置进行定制/重写,甚至包括、等,尽管在实际应用中,这样的需求并不常见。关于iBatis上述分析只适合iBatis之后的版本。在iBatis2.1.5中,addSqlMapNodelets是SqlMiipConEgParser的私有成员函数,无法在子类中重写。附件中,我们给出了针对iBatis2.1.5的SqlMapConfigParserEx实现,大致思想类似,这里就不再详述。结束语iBatis作为一个ORM框架,以其简洁易用,支持更为敏捷的数据库/系统设计,正在得到越来越多的关注。iBatis应用中,开发者需要自己编写详细的SQL语句,针对特定的数据库进行SQL优化,处理跨数据库平台移植问题等。木文,针对iBatis应用中的多数据库支持问题,通过扩展iBatis的现有实现,给出了一个较为简洁高效的解决方法。

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

当前位置:首页 > 在线阅读 > 生活休闲


备案号:宁ICP备20000045号-1

经营许可证:宁B2-20210002

宁公网安备 64010402000986号