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的主配置文件:




	
	
		
		
		
		
		
	
	
		
			
			
			
				
				
				
				
				
				
			
		
	
	
		
		
		
	
	
		
	

配置当中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等,这个实现刚好对应了我们上面配置的的属性,或者配置为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;
   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
   Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
  List 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的一个引用而已。

你可能感兴趣的:(MyBatis)