1. Mybatis的基本构成
2. SqlSession和SqlSessionFactory的接口定义
总的来说SqlSession接口定义了一系列CRUD的方法,Mybatis框架在最底层就是用这些接口方法对数据库进行操作。
SqlSession的实现类拥有四大组件:Executor, StatementHandler, ParameterHandler, ResultHandler。
public interface SqlSession extends Closeable {
T selectOne(String var1);
T selectOne(String var1, Object var2);
List selectList(String var1);
List selectList(String var1, Object var2);
List selectList(String var1, Object var2, RowBounds var3);
Map selectMap(String var1, String var2);
Map selectMap(String var1, Object var2, String var3);
Map selectMap(String var1, Object var2, String var3, RowBounds var4);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
int delete(String var1);
int delete(String var1, Object var2);
void commit();
void commit(boolean var1);
void rollback();
void rollback(boolean var1);
List flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
T getMapper(Class var1);
Connection getConnection();
}
SqlSessionFactory 则是用来创建SqlSession的
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
SqlSession的实现类是DefaultSqlSession和SqlSessionManager
SqlSessionFactory的实现类是:DefaultSqlSessionFactory和SqlSessionManager
2. 看看DefaultSqlSession的select方法的实现,其他的方法主题思想大同小异:
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
可以看出,主要都是从Configuration对象中取出MappedStatement,然后交给executor去执行。
DefaultSqlSessionFactory的部分源码:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//...
这里使用configuration创建出了executor,这个executor作为四大组件之一(四大组件包括execturo,statementHandler,parameterHandler, resultHandler),是所有mybatis请求的执行入口,他调用了其他三大组建共同完成了对数据库的操作。
SqlSessionManager的源码:
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
// proxy
private final SqlSession sqlSessionProxy;
// 保持线程局部变量SqlSession的地方
private ThreadLocal localSqlSession = new ThreadLocal();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
// 这个proxy是重点
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
public static SqlSessionManager newInstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
public static SqlSessionManager newInstance(Reader reader, String environment) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
}
//...
// 设置线程局部变量sqlSession的方法
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
public void startManagedSession(boolean autoCommit) {
this.localSqlSession.set(openSession(autoCommit));
}
//...
@Override
public T selectOne(String statement, Object parameter) {
return sqlSessionProxy. selectOne(statement, parameter);
}
@Override
public Map selectMap(String statement, String mapKey) {
return sqlSessionProxy. selectMap(statement, mapKey);
}
变量sqlSessionFactory:相当于DefaultSqlSessionFactory的实例(不是proxy)。
所有的调用sqlSessionProxy代理对象的C、R、U、D及事务方法,都将经过SqlSessionInterceptor拦截器,并最终由目标对象target实际完成数据库操作。
SqlSessionInterceptor源码
private class SqlSessionInterceptor implements InvocationHandler {
public SqlSessionInterceptor() {
// Prevent Synthetic Access
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
// 1、存在线程局部变量sqlSession(不提交、不回滚、不关闭,可在线程生命周期内,自定义sqlSession的提交、回滚、关闭时机,达到复用sqlSession的效果)
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
// 2、不存在线程局部变量sqlSession,创建一个自动提交、回滚、关闭的SqlSession(提交、回滚、关闭,将sqlSession的生命周期完全限定在方法内部)
final SqlSession autoSqlSession = openSession();
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
} finally {
autoSqlSession.close();
}
}
}
}
3.生命周期
SqlSessionFactoryBuilder: 一旦构建好Sql'SessionFactory,就可以将Builder销毁
SqlSessionFactory: 因为SqlSession需要多次创建,所以SqlSessionFactory的生命周期应该是MyBatis的存在时间
SqlSession:完成一次操作后即收回,当然如果我们用池子,那是另外一回事儿。
Mapper:和SqlSession同生命周期?