1、sqlsession:
sqlsession是由SqlSessionFactory(SqlSessionFactory一旦被创建就在应用的运行期间一直存在)创建,在跟spring结合以前sqlsession实际是由SqlSessionManager创建管理,在spring中mybatis专门有个类SqlSessionTemplate替代SqlSessionManager的工作。
SqlSessionTemplate是单例的,并且实现的是SqlSession, DisposableBean接口,可以将SqlSessionTemplate理解为SqlSession的代理。
//删除了一些sqlsession的实现方法,这些方法都跟selectOne一样
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
//这个是重点,所有SqlSession的实现都是由这个代理实现的
private final SqlSession sqlSessionProxy;
private final PersistenceExceptionTranslator exceptionTranslator;
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
}
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
}
//重要
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
Assert.notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
//关键
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}
/**
*在调用此方法后,实际执行为SqlSessionInterceptor.invoke,由代码可见sqlSession由SqlSessionUtils创建,
**/
public <T> T selectOne(String statement) {
return this.sqlSessionProxy.selectOne(statement);
}
private class SqlSessionInterceptor implements InvocationHandler {
private SqlSessionInterceptor() {
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
Object unwrapped;
try {
Object result = method.invoke(sqlSession, args);
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
unwrapped = result;
} catch (Throwable var11) {
unwrapped = ExceptionUtil.unwrapThrowable(var11);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw (Throwable)unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
return unwrapped;
}
}
}
//这是SqlSessionUtils的创建sqlsession的地方,可以简单理解为如果没有sqlsession就创建一个并放入ThreadLocal中保存,否则从ThreadLocal中取出
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
Assert.notNull(executorType, "No ExecutorType specified");
SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Creating a new SqlSession");
}
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
}
根据以上代码可知sqlSession实际是每个线程都会创建一个,生命周期依附于其调用线程。
2、Executor:sqlSession执行sql的执行器:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
Executor种类有几个:
- BaseExecutor:是Executor的一个子类,是一个抽象类,其实现了接口Executor的部分方法,并提供了三个抽象方法doUpdate、doFlushStatements和doQuery在他的子类SimpleExecutor、ReuseExecutor和BatchExecutor中实现
- SimpleExecutor:通过类名可以看出,它是一个简单的执行类,并不会做一些处理就执行sql
- CachingExecutor:这个Executor执行类是使用内存的,将数据保存到缓存中,这样可以有效的解决增删改查性能。缓存的作用域为mapper(namespace),所以同一个namespace的操作会影响到相同作用域下的缓存。
- BatchExecutor:顾名思义就是进行批量操作,通过批量操作来提高性能。
- ReuseExecutor:顾名思义就是重复使用执行,其定义了一个Map<String, Statement>,将执行的sql作为key,将执行的Statement作为value保存,这样执行相同的sql时就可以使用已经存在的Statement,就不需要新创建了
3、Connection对象是和数据库建立的通信连接对象,执行sql的底层逻辑就要通过Connection对象实现。
SqlSession是通过各种Executor获取connection并执行sql
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
flushStatements();
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
4、连接池:
往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费,所以就有了连接池,mybatis的连接池是PooledDataSource,其中包了一个UnpooledDataSource。
上面获取Connection的代码中有一行
Connection connection = getConnection(ms.getStatementLog());
getConnection代码如下:
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = this.transaction.getConnection();
return statementLog.isDebugEnabled() ? ConnectionLogger.newInstance(connection, statementLog, this.queryStack) : connection;
}
继续往下追:
SpringManagedTransaction的getConnection
public Connection getConnection() throws SQLException {
if (this.connection == null) {
this.openConnection();
}
return this.connection;
}
private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");
}
}
DataSourceUtils.getConnection(this.dataSource)中的dataSource就是连接池,至于是采用的Mybatis自己的连接池还是spring自己写的连接池就无关紧要了。
综上sqlsession/Executor/Connection/连接池他们的关系就已经清晰了,sqlsession在各个线程中创建,根据策略选择Executor,Executor在连接池中获取Connection,最后由Connection作为底层执行sql。至于连接池中Connection的生命周期就是另一个问题了。