在Spring 中集成iBatis的配置是很简单了,下面是一个简单的配置示例:
Spring 的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
">
<context:component-scan base-package="com.david.demo.common.*" />
<context:property-placeholder location="classpath:META-INF/config.properties" />
<!-- 定义数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.ams.driver}" />
<property name="jdbcUrl" value="${jdbc.ams.url}" />
<property name="user" value="${jdbc.ams.username}" />
<property name="password" value="${jdbc.ams.password}" />
<property name="initialPoolSize" value="${initialSize}" />
<property name="minPoolSize" value="${minPoolSize}" />
<property name="maxPoolSize" value="${maxActive}" />
<property name="acquireIncrement" value="${acquireIncrement}" />
<property name="maxIdleTime" value="${maxIdleTime}" />
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:META-INF/sqlmap/sqlmap.xml" />
</bean>
</beans>
config.properties
jdbc.ams.driver=com.mysql.jdbc.Driver
jdbc.ams.url=jdbc:mysql://localhost:3306/test
jdbc.ams.username=root
jdbc.ams.password=root
initialSize=3
minPoolSize=5
maxActive=100
acquireIncrement=3
maxIdleTime=10
sqlMap.xml
<?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>
<!--
cacheModelsEnable 是否启用sqlMapClient上的缓存机制,
enhancementEnabled 是否省队POJO启用字节码增强,提升getter/setter效率
lazyLoadingEnabled 是否启用延迟加载机制
errorTracingEnable 是否启用错误日志
maxRequest 最大并发请求数(Statement 并发数)
maxSession 最大Session数(SqlMapClient 并发数) maxTransaction=<maxSession=<maxRequest
maxTransactions 最大并发事务
useStatemnetNamespaces 是否启用命名空间
-->
<settings cacheModelsEnabled="false" enhancementEnabled="true"
lazyLoadingEnabled="true" errorTracingEnabled="true" useStatementNamespaces="true" maxRequests="3000"
maxSessions="3000" maxTransactions="3000" />
<sqlMap resource="META-INF/sqlmap/sqlmap-Book.xml" />
</sqlMapConfig>
sqlmap-Book.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="demo">
<resultMap class="com.david.common.domain.Book" id="BooKMap">
<result property="id" column="id" javaType="int" />
<result property="name" column="name" javaType="java.lang.String" />
<result property="price" column="price" javaType="int" nullValue="0" />
<result property="extend" column="extend" typeHandler="com.david.demo.common.handler.ExtendTypeHandler"/>
</resultMap>
<typeAlias alias="Book" type="com.david.common.domain.Book" />
<parameterMap class="Book" id="book">
<parameter property="name" javaType="java.lang.String" nullValue="test"/>
<parameter property="price" javaType="int" nullValue="0"/>
<parameter property="extend" typeHandler="com.david.demo.common.handler.ExtendTypeHandler" />
</parameterMap>
<insert id="insert" parameterMap="book">
insert into t_book (name,price,extend) values (?,?,?)
<selectKey keyProperty="id" resultClass="Integer">
select
LAST_INSERT_ID()
</selectKey>
</insert>
<select id="select-all" resultMap="BooKMap">
select id,name,price,extend,gmt_create,gmt_modify from t_book
</select>
<delete id="delete-by-id">
delete from t_book where id=#id#
</delete>
</sqlMap>
iBatis执行SQL的关键入口是SqlMapClientImpl。通过该类的源码可以发现,在构造方法中注入了一个SqlMapExecutorDelegate 实例,但该类并不真正执行Sql 而是通过SqlMapSession去执行的。
/**
* Implementation of ExtendedSqlMapClient
*/
public class SqlMapClientImpl implements SqlMapClient, ExtendedSqlMapClient {
private static final Log log = LogFactory.getLog(SqlMapClientImpl.class);
/**
* 执行SQL的代理
*/
public SqlMapExecutorDelegate delegate;
protected ThreadLocal localSqlMapSession = new ThreadLocal();
/**
* Constructor to supply a delegate
*
* @param delegate - the delegate
*/
public SqlMapClientImpl(SqlMapExecutorDelegate delegate) {
this.delegate = delegate;
}
public Object insert(String id, Object param) throws SQLException {
return getLocalSqlMapSession().insert(id, param);
}
...
/**
获取当前线程的SqlMapSession,如果当前线程中没有SqlMapSession或SqlMapSession已经关闭,则创建一个新的SqlMapSession 并存入到当前线程中。
*/
protected SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
// 使用当前SqlMapClientImpl 作为构造参数构造一个新的SqlMapSession实例
sqlMapSession = new SqlMapSessionImpl(this);
// 将实例放入ThreadLocal中
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
...
}
通过SqlMapSessionImpl 的源码可以发现,在构造函数中,将SqlMapClientImpl中的属性delegate赋值给了SqlMapSessionImpl的属性delegate,同时可以发现SqlMapExecutorDelegate是真正执行Sql的地方
**
* Implementation of SqlMapSession
*/
public class SqlMapSessionImpl implements SqlMapSession {
protected SqlMapExecutorDelegate delegate;
protected SessionScope sessionScope;
protected boolean closed;
/**
* Constructor
*
* @param client - the client that will use the session
*/
public SqlMapSessionImpl(SqlMapClientImpl client) {
this.delegate = client.getDelegate();
this.sessionScope = this.delegate.beginSessionScope();
this.sessionScope.setSqlMapClient(client);
this.sessionScope.setSqlMapExecutor(client);
this.sessionScope.setSqlMapTxMgr(client);
this.closed = false;
}
/**
* Start the session
*/
public void open() {
sessionScope.setSqlMapTxMgr(this);
}
/**
* Getter to tell if the session is still open
*
* @return - the status of the session
*/
public boolean isClosed() {
return closed;
}
public void close() {
if (delegate != null && sessionScope != null) delegate.endSessionScope(sessionScope);
if (sessionScope != null) sessionScope = null;
if (delegate != null) delegate = null;
if (!closed) closed = true;
}
// 使用SqlMapExecutorDelegate去执行SQL
public Object insert(String id, Object param) throws SQLException {
return delegate.insert(sessionScope, id, param);
}
...