使用iBatis作为持久层实现快速开发

本文介绍了如何利用iBatis作为持久层框架实现快速开发,强调了使用持久层框架可以避免内存泄露等错误,提高代码可维护性,并提供了详细的步骤,包括数据库设计、iBatis配置、DAO及Service层的实现,旨在帮助开发者更专注于业务逻辑。
摘要由CSDN通过智能技术生成

可能大家对iBatis的开发使用已经能够耳熟能详了,但是我们这里并非是对一个新的持久层方案做推广式的介绍,我想说的是,使用任何一个持久层解决方案,都应该能很好地将屏蔽物理数据库的复杂性,iBatis也一样。然而,对于开发人员来说,甚至是经历比较资深的程序员,在选择持久层方案与JDBC直连的时候,往往都会觉得iBatis配置比较复杂,而直接使用JDBC可以非常游刃有余地写出复杂容易理解的SQL语句,实现比较复杂的业务,但是他们也会“偶尔”因为管理资源不当,导致内存泄露,比如忘记关闭连接,对于交易系统来说,严重的话很可能直接造成整个系统宕机。对于一些初级的程序员(接触数据库应用开发时间不长),发生这样错误的可能性就更大了,而且由于代码经过多人之手多次重构,想要排查错误可能要从一堆乱糟糟的代码之中,一点点地找到问题所在,代价实在很大。

所以,我在开发中一般鼓励程序员使用持久层框架来做数据访问层(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)
);

第二步:生成iBatis持久层配置

使用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();

 

其实,有了上面这些作为基础,开发人员在开发过程甚至感觉不到是在调用数据库,而只是在调用一组与自己实现业务逻辑相关的服务。而且,开发人员可以在完成业务逻辑代码的过程中,处理好异常,关注自己代码的性能和健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值