使用iBatis作为持久层实现快速开发
2012-12-02 16:52
323 查看
可能大家对iBatis的开发使用已经能够耳熟能详了,但是我们这里并非是对一个新的持久层方案做推广式的介绍,我想说的是,使用任何一个持久层解决方案,都应该能很好地将屏蔽物理数据库的复杂性,iBatis也一样。然而,对于开发人员来说,甚至是经历比较资深的程序员,在选择持久层方案与JDBC直连的时候,往往都会觉得iBatis配置比较复杂,而直接使用JDBC可以非常游刃有余地写出复杂容易理解的SQL语句,实现比较复杂的业务,但是他们也会“偶尔”因为管理资源不当,导致内存泄露,比如忘记关闭连接,对于交易系统来说,严重的话很可能直接造成整个系统宕机。对于一些初级的程序员(接触数据库应用开发时间不长),发生这样错误的可能性就更大了,而且由于代码经过多人之手多次重构,想要排查错误可能要从一堆乱糟糟的代码之中,一点点地找到问题所在,代价实在很大。
所以,我在开发中一般鼓励程序员使用持久层框架来做数据访问层(DAL),甚至,一个业务系统前期上线并没有考虑到后期可能要统计出报表,在后期的升级开发过程中,我也建议使用持久层框架,像iBatis就可以很好地支持任意复杂SQL语句,你可以将你写的SQL语句直接通过CDATA来避免iBatis解析器去解析,而直接在运行时执行你所实现的SQL语句查询,如下所示:
一般来说,在系统上线之前,程序的逻辑错误导致的BUG基本都能够发现并修正,而对于一些比较隐藏的错误,例如内存泄露等,可能只要在系统使用一段时间以后才会出现,对这样的错误的排查可能也要花费时间和力气。而是用一些开源的解决方案的好处是,将一些复杂、容易出错的地方都在框架层解决掉,即使是系统上线后因为框架的问题,排查错误基本定位在框架这一层,而不需要排查每一个程序员开发的代码,而只需要通过开源社区对问题的跟踪和解决来完善我们的系统。使用框架的另一个好处是,能够是开发人员集中精力做好业务逻辑代码的处理。可能,在使用持久层框架的过程中,花费的时间多一点(针对那些并非很熟悉框架配置的人员),但是最终我们能够从这里受益的,甚至节约了更多的code
review的时间和精力。
下面,总结介绍一个使用iBatis作为持久层方案实现系统的数据库访问层以及服务层的代码框架:
第一步:实例数据库设计
我比较习惯使用Eclipse的ERMaster插件来对数据进行建模,它可以直接从ER图生成建表DDL,如图所示:
生成建表SQL语句如下:
第二步:[b]生成iBatis持久层配置[/b]
使用Eclipse,需要安装一个iBator插件,然后配置如下:
通过插件,就可以生成表de_pc_keywords对应DAO、DAO实现及其Map配置。
第三步:配置iBatis全局配置
全局iBatis配置可以配置数据库连接池、账号、表映射配置等等,如下所示:
上面使用了DBCP连接池,而且数据库的配置信息从属性文件“database.properties”文件中读取。
如果你的应用需要多张表,可以配置多个sqlMap元素。
第四步:配置DAO
配置内容,如下所示:
第五步:加载iBatis配置并开发Service框架
我们能够获取到DAO实例,就能通过它来访问数据库,实现代码如下所示:
在开发过程中,为了开发人员集中精力实现复杂的业务逻辑,我们可以在DAO层基础上实现通用的Service层,这样开发人员只需要在Service层中增加自己需要的对数据库的操作,即可在实现业务逻辑时方便地调用。实现的CommonService泛型类如下:
使用任何一个表对应的DAO实现,都可以通过上面泛型在实际的Service类中注入。下面,看看我们实现的Service接口和实现类:
在实现类中,可以继承自我们上面实现的CommonService泛型类,如下所示:
第六步:调用Service实现
其实,开发人员只需要在实际需要调用Service的地方,new一个Service实现类的实例即可,而且无需关心DAO层,如下所示:
其实,有了上面这些作为基础,开发人员在开发过程甚至感觉不到是在调用数据库,而只是在调用一组与自己实现业务逻辑相关的服务。而且,开发人员可以在完成业务逻辑代码的过程中,处理好异常,关注自己代码的性能和健壮性。
所以,我在开发中一般鼓励程序员使用持久层框架来做数据访问层(DAL),甚至,一个业务系统前期上线并没有考虑到后期可能要统计出报表,在后期的升级开发过程中,我也建议使用持久层框架,像iBatis就可以很好地支持任意复杂SQL语句,你可以将你写的SQL语句直接通过CDATA来避免iBatis解析器去解析,而直接在运行时执行你所实现的SQL语句查询,如下所示:
<sqlMap namespace="marketing_data_stat"> <resultMap id="stat_ssl_result_map" class="org.shirdrn.wm.de.db.model.MarketingDataStat"> <result column="domain" property="domain" jdbcType="VARCHAR" /> <result column="count" property="count" jdbcType="INT" /> </resultMap> <select id="stat_count_ssl" parameterClass="java.util.HashMap" resultClass="org.shirdrn.wm.de.db.model.MarketingDataStat"> <![CDATA[ select primary_domain as domain, count(cert_issuer_brand) as count from marketing_data where (cert_validation='DV' or cert_validation='EV' or cert_validation='OV') and cert_validity_notBefore<=DATE(NOW()) and cert_validity_notAfter >=DATE(NOW()) and cert_issuer_brand!='' and created_at<DATE(NOW()) and cert_url_isNameMatch='Y' and live=1 group by primary_domain order by count desc ]]> <dynamic prepend="limit"> #limit:INT# </dynamic> </select> </sqlMap>
一般来说,在系统上线之前,程序的逻辑错误导致的BUG基本都能够发现并修正,而对于一些比较隐藏的错误,例如内存泄露等,可能只要在系统使用一段时间以后才会出现,对这样的错误的排查可能也要花费时间和力气。而是用一些开源的解决方案的好处是,将一些复杂、容易出错的地方都在框架层解决掉,即使是系统上线后因为框架的问题,排查错误基本定位在框架这一层,而不需要排查每一个程序员开发的代码,而只需要通过开源社区对问题的跟踪和解决来完善我们的系统。使用框架的另一个好处是,能够是开发人员集中精力做好业务逻辑代码的处理。可能,在使用持久层框架的过程中,花费的时间多一点(针对那些并非很熟悉框架配置的人员),但是最终我们能够从这里受益的,甚至节约了更多的code
review的时间和精力。
下面,总结介绍一个使用iBatis作为持久层方案实现系统的数据库访问层以及服务层的代码框架:
第一步:实例数据库设计
我比较习惯使用Eclipse的ERMaster插件来对数据进行建模,它可以直接从ER图生成建表DDL,如图所示:
生成建表SQL语句如下:
CREATE TABLE DE_PC_KEYWORDS ( ID INT NOT NULL UNIQUE AUTO_INCREMENT, DOMAIN VARCHAR(255) NOT NULL, KEYWORD VARCHAR(255) NOT NULL, TYPE TINYINT NOT NULL, STATUS TINYINT NOT NULL, CREATED_AT DATE NOT NULL, UPDATED_AT TIMESTAMP NOT NULL, PRIMARY KEY (ID) );
第二步:[b]生成iBatis持久层配置[/b]
使用Eclipse,需要安装一个iBator插件,然后配置如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ibatorConfiguration PUBLIC "-//Apache Software Foundation//DTD Apache iBATIS Ibator Configuration 1.0//EN" "http://ibatis.apache.org/dtd/ibator-config_1_0.dtd"> <ibatorConfiguration> <classPathEntry location="/home/shirdrn/programs/eclipse-java-juno/workspace/ad_kw_platform/lib/mysql-connector-java-5.1.7-bin.jar" /> <ibatorContext id="ad_kw_platform" targetRuntime="Ibatis2Java5"> <property name="autoDelimitKeywords" value="true" /> <ibatorPlugin type="org.apache.ibatis.ibator.plugins.EqualsHashCodePlugin" /> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://172.0.8.249:5606/ad_kw_db?useUnicode=true" userId="root" password=$%@GFDsf00_o0pw /> <javaModelGenerator targetPackage="org.shirdrn.wm.de.db.model" targetProject="ad_kw_platform"> <property name="enableSubPackages" value="true" /> </javaModelGenerator> <sqlMapGenerator targetPackage="org.shirdrn.wm.de.db.model.sqlmap" targetProject="ad_kw_platform"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <daoGenerator targetPackage="org.shirdrn.wm.de.db.dao" targetProject="ad_kw_platform" type="IBATIS" implementationPackage="org.shirdrn.wm.de.db.dao.impl"> <property name="enableSubPackages" value="true" /> </daoGenerator> <table tableName="de_pc_keywords" modelType="flat"> <generatedKey column="id" sqlStatement="MySql" identity="true" type="post" /> </table> </ibatorContext> </ibatorConfiguration>
通过插件,就可以生成表de_pc_keywords对应DAO、DAO实现及其Map配置。
第三步:配置iBatis全局配置
全局iBatis配置可以配置数据库连接池、账号、表映射配置等等,如下所示:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <properties resource="database.properties" /> <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" maxRequests="128" maxSessions="64" maxTransactions="16" useStatementNamespaces="true" /> <transactionManager type="JDBC"> <dataSource type="DBCP"> <property name="JDBC.Driver" value="${db.common.driver}" /> <property name="JDBC.ConnectionURL" value="${db.de.url}" /> <property name="JDBC.Username" value="${db.de.username}" /> <property name="JDBC.Password" value="${db.de.password}" /> <property name="initialSize" value="1" /> <property name="maxActive" value="50" /> <property name="maxIdle" value="10" /> <property name="minIdle" value="5" /> <property name="maxWait" value="60000" /> <!-- Use of the validation query can be problematic. If you have difficulty, try without it. --> <property name="validationQuery" value="select null from dual" /> <property name="poolPreparedStatements" value="true" /> <property name="logAbandoned" value="false" /> <property name="removeAbandoned" value="true" /> <property name="removeAbandonedTimeout" value="300" /> <property name="defaultAutoCommit" value="false" /> <property name="defaultTransactionIsolation" value="NONE" /> </dataSource> </transactionManager> <!-- List the SQL Map XML files. They can be loaded from the classpath, as they are here (com.marketing.data...) --> <sqlMap resource="org/shirdrn/wm/de/db/model/sqlmap/de_pc_keywords_SqlMap.xml" /> </sqlMapConfig>
上面使用了DBCP连接池,而且数据库的配置信息从属性文件“database.properties”文件中读取。
如果你的应用需要多张表,可以配置多个sqlMap元素。
第四步:配置DAO
配置内容,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE daoConfig PUBLIC "-//ibatis.apache.org//DTD DAO Configuration 2.0//EN" "http://ibatis.apache.org/dtd/dao-2.dtd"> <daoConfig> <context> <transactionManager type="SQLMAP"> <property name="SqlMapConfigResource" value="org/shirdrn/wm/de/db/sqlmap/db_SqlMap.xml" /> </transactionManager> <dao interface="org.shirdrn.wm.de.db.dao.DePcKeywordsDAO" implementation="org.shirdrn.wm.de.db.dao.impl.DePcKeywordsDAOImpl" /> </context> </daoConfig>
第五步:加载iBatis配置并开发Service框架
我们能够获取到DAO实例,就能通过它来访问数据库,实现代码如下所示:
package org.shirdrn.wm.de.db; import java.io.IOException; import java.io.Reader; import java.util.Properties; import com.ibatis.common.resources.Resources; import com.ibatis.dao.client.DaoManager; import com.ibatis.dao.client.DaoManagerBuilder; public class DeDaoConfig { private static final String resourceStaging = "dao/dao.xml"; private static DaoManager daoManager = null; static { try { daoManager = newDaoManager(null); } catch (Exception e) { e.printStackTrace(); Runtime.getRuntime().exit(-1); } } public static DaoManager getDaoManager() { return daoManager; } private static DaoManager newDaoManager(Properties props) throws IOException { Reader reader = Resources.getResourceAsReader(resourceStaging); return DaoManagerBuilder.buildDaoManager(reader, props); } }
在开发过程中,为了开发人员集中精力实现复杂的业务逻辑,我们可以在DAO层基础上实现通用的Service层,这样开发人员只需要在Service层中增加自己需要的对数据库的操作,即可在实现业务逻辑时方便地调用。实现的CommonService泛型类如下:
package org.shirdrn.wm.de.common.service; import org.shirdrn.wm.de.db.DeDaoConfig; /** * Common abstract service for injecting DAO to services * which implement this class. * * @author Shirdrn * * @param <T> DAO {@link Class} */ public abstract class DeCommonService<T> { protected T dao; public DeCommonService() { super(); } @SuppressWarnings("unchecked") protected DeCommonService(Class<T> clazz) { super(); this.dao = (T) DeDaoConfig.getDaoManager().getDao(clazz); } }
使用任何一个表对应的DAO实现,都可以通过上面泛型在实际的Service类中注入。下面,看看我们实现的Service接口和实现类:
package org.shirdrn.wm.de.service; import java.util.List; import org.shirdrn.wm.de.db.model.DePcKeywords; import org.shirdrn.wm.de.db.model.DePcKeywordsExample; public interface DePcKeywordsService { public int insert(DePcKeywords keyword); public List<DePcKeywords> query(DePcKeywordsExample example); public int update(DePcKeywords keyword); }
在实现类中,可以继承自我们上面实现的CommonService泛型类,如下所示:
package org.shirdrn.wm.de.service.impl; import java.util.List; import org.shirdrn.wm.de.common.service.DeCommonService; import org.shirdrn.wm.de.db.dao.DePcKeywordsDAO; import org.shirdrn.wm.de.db.model.DePcKeywords; import org.shirdrn.wm.de.db.model.DePcKeywordsExample; import org.shirdrn.wm.de.service.DePcKeywordsService; public class DePcKeywordsServiceImpl extends DeCommonService<DePcKeywordsDAO> implements DePcKeywordsService { public DePcKeywordsServiceImpl() { super(DePcKeywordsDAO.class); } @Override public int insert(DePcKeywords keyword) { return dao.insertSelective(keyword); } @Override public List<DePcKeywords> query(DePcKeywordsExample example) { return dao.selectByExample(example); } @Override public int update(DePcKeywords keyword) { return dao.updateByPrimaryKeySelective(keyword); } }
第六步:调用Service实现
其实,开发人员只需要在实际需要调用Service的地方,new一个Service实现类的实例即可,而且无需关心DAO层,如下所示:
private static final DePcKeywordsService dePcKeywordsService = new DePcKeywordsServiceImpl();
其实,有了上面这些作为基础,开发人员在开发过程甚至感觉不到是在调用数据库,而只是在调用一组与自己实现业务逻辑相关的服务。而且,开发人员可以在完成业务逻辑代码的过程中,处理好异常,关注自己代码的性能和健壮性。
相关文章推荐
- 使用Andbase快速开发框架实现常见侧滑栏和滑动标签页组合效果
- openjweb快速开发平台中使用Groovy动态语言作为规则引擎解决方案
- openjweb快速开发平台中使用Groovy动态语言作为规则引擎解决方案
- 【Android进阶】使用Andbase快速开发框架实现常见侧滑栏和滑动标签页组合效果
- 介绍一种免xml配置的持久层实现快速开发的框架
- 【Android进阶】使用Andbase快速开发框架实现常见侧滑栏和滑动标签页组合效果
- 使用BrowserSync实现页面实时刷新、进行快速开发
- 快速开发android应用2-使用TextInputLayout实现用户登录及验证
- C#应用XML作为数据库的快速开发框架实现方法
- 介绍一种免xml配置的持久层实现快速开发的框架
- OpenJWeb快速开发平台使用struts2实现多语切换的方法
- Android开发:使用AutoInputAuthCode快速实现自动填写验证码
- OpenJWeb快速开发平台使用struts2实现多语切换的方法
- 快速开发android应用5-使用picasso实现轮播图
- Android使用Andbase快速开发框架实现常见侧滑栏和滑动标签页组合效果
- 使用 Chrome 开发者工具实现网站快速开发的12个小技巧
- Android一点 简单的监听器使用,实现开发时逻辑和view的分离
- 【Android UI设计与开发】第02期:引导界面(二)使用ViewPager实现欢迎引导页面
- Objective-C ,ios,iphone开发基础:使用第三方库FMDB连接sqlite3 数据库,实现简单的登录
- Android开发之使用VideoView实现视频的横屏播放、去除边框