MyBatis如何管理数据库连接

    这里讲述的相关信息是单纯MyBatis相关的,不涉及Spring,代码是基于mybatis-3.4.6,MyBatis之所以能够配置第三方的连接池,主要得益于java在数据库连接上作的规范接口,如javax.sql.DataSource,这个接口只有两个方法:

public interface DataSource  extends CommonDataSource, Wrapper {
  Connection getConnection() throws SQLException;
  Connection getConnection(String username, String password) throws SQLException;
}

由此可见,Java认为数据源就是一个提供特定数据库连接的接口,除此以外,不提供任何功能,当然,连接的管理、关闭等由数据源具体实现去做,数据源的含义必须理解透彻。

    MyBatis针对DataSource接口做了两个实现:

UnpooledDataSource所作的工作就是直接通过DriverManager取得连接并返回,PooledDataSource就会维护一个连接池,这个池是PoolState,作为数据成员存在于PooledDataSource中,从PooledDataSource中取连接和关闭连接都是PoolState操作完成的,同时,创建新连接是使用UnpooledDataSource,也即PooledDataSource会聚合UnpooledDataSource作为数据成员。

接下来我们讨论下MyBatis使用第三方连接池的原理,这里先来看下一个不使用Spring的Java工程中MyBatis的主配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<properties resource="dbconfig.properties" />
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<setting name="jdbcTypeForNull" value="NULL" />
		<setting name="cacheEnabled" value="true" />
		<setting name="lazyLoadingEnabled" value="true" />
		<setting name="aggressiveLazyLoading" value="false" />
	</settings>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC">
			</transactionManager>
			<dataSource type="com.asimpleland.dao.DruidDataSourceFactory">
				<property name="driverClassName" value="${driverClassName}"></property>
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
				<property name="initialSize" value="${initialSize}" />
				<property name="maxActive" value="${maxActive}" />
			</dataSource>
		</environment>
	</environments>
	<databaseIdProvider type="DB_VENDOR">
		<property name="MySQL" value="mysql" />
		<property name="Oracle" value="oracle" />
		<property name="SQL Server" value="sqlserver" />
	</databaseIdProvider>
	<mappers>
		<mapper resource="com/asimpleland/dao/sqlmap/TestMapper.xml" />
	</mappers>
</configuration>

配置当中DruidDataSourceFactory是自定义的一个类,

public class DruidDataSourceFactory extends UnpooledDataSourceFactory{
    public DruidDataSourceFactory(){
        this.dataSource = new DruidDataSource();
    }
}

从这里可以看出,Druid连接池就是以数据源形式嵌入MyBatis的,那么在MyBatis中谁持有DataSource,就是入口了,这个类就是java.sql.Connection.Transaction的实现类,MyBatis提供了两个实现类:

其中JdbcTransaction对应的是原生jdbc事务的使用,ManagedTransaction是将事务托管给web容器的,如WebLogic等,这个实现刚好对应了我们上面配置的<transactionManager type="JDBC">的属性,或者配置为type="MANAGED"。

    在Java接口规范中,事务相关功能是聚合在Connection里面的,或者说,编程人员是通过Connection接口来使用jdbc事务的,所以MyBatis的设计中,JdbcTransaction就是聚合了Connection和DataSource,以此来封装事务能力,那么我们每次使用SqlSession来执行sql时就必然使用到Connection,在SqlSession中有个方法可以获取连接:

@Override
public Connection getConnection() {
	try {
		return executor.getTransaction().getConnection();
	} catch (SQLException e) {
		throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
	}
}

从这里可以看出,连接被封装在Executor中的Transaction中,那我们来看看Executor接口是什么:

public interface Executor {
  ResultHandler NO_RESULT_HANDLER = null;
  int update(MappedStatement ms, Object parameter) throws SQLException;
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
  List<BatchResult> flushStatements() throws SQLException;
  void commit(boolean required) throws SQLException;
  void rollback(boolean required) throws SQLException;
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
  boolean isCached(MappedStatement ms, CacheKey key);
  void clearLocalCache();
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
  Transaction getTransaction();
  void close(boolean forceRollback);
  boolean isClosed();
  void setExecutorWrapper(Executor executor);
}

可以看到,MyBatis将数据库操作封装到Executor中,Executor接口有一个抽象实现和一个具体实现类:

BaseExecutor抽象类中聚合了Transaction,到这里,我们基本上把整个流程串起来了,MyBatis中,首先通过SqlSessionFactory获取SqlSession,由SqlSession来执行sql语句,SqlSession中由Excutor实现sql语句执行,Excutor中聚合Transaction,Transaction聚合了Connection和DataSource,能够获取到连接,所有的语句最终交给Connection实现,Connection的具体实现就是jdbc驱动完成的了,其实底层所有工作还是jdbc驱动做的,要理解这个,必须要有jdbc编程经验,否则无法真正快速理解,MyBatis中封装的Connection只是jdbc Connection的一个引用而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值