一、前言
本文只专注于myabtis Sql的调用过程,对于相关方法的细节并没有详细的介绍,如果有学习的欲望,可根据下文中的介绍的类和方法自行学习
二、正文
本文通过继承SqlSessionDaoSupport的方式直接通过sqlSession访问数据库。还有一种方式是通过定义接口来访问,其实这种方式的底层也是生成代理对象,通过sqlsession访问的。
@Repository
public class Dao extends SqlSessionDaoSupport {
/**
* 设置工厂类
*
* @param sqlSessionFactory sql工厂类
*/
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
public <T> T get(String prefix,String key,Object params){
return getSqlSession().selectOne(prefix+key,params);
}
public void insert(String prefix,String key,Object params){
getSqlSession().insert(prefix+key,params);
}
public void update(String prefix,String key,Object params){
getSqlSession().update(prefix+key,params);
}
public void delete(String prefix,String key,Object params){
getSqlSession().delete(prefix+key,params);
}
public <T> List<T> getList(String prefix, String key, Object params) {
return this.getSqlSession().selectList(prefix + key, params);
}
/**
* 获取分页的数据
* @param prefix
* @param key
* @param params
* @param page
* @return
*/
public Page page(String prefix, String key, Map<String,Object> params, Page page) {
params.put("page",page);
page.setList(this.getSqlSession().selectList(prefix + key, params));
return page;
}
SqlSession 接口中定义了很多增删改的方法,我们可以通过重写这个方法来进行数据库的访问。
public interface SqlSession extends Closeable {
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> 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<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
此处我们只针对于this.getSqlSession().selectList()的方法来跟踪sql的执行过程,我们先看getSqlSession方法看看到底是个什么东西。
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
public SqlSessionDaoSupport() {
}
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
public SqlSession getSqlSession() {
return this.sqlSession;
}
protected void checkDaoConfig() {
Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}
}
看的出来这个SqlSession实际类型是SqlSessionTemplate对象,下面我们看一下这个对象的构造方法
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());
}
public SqlSessionFactory getSqlSessionFactory() {
return this.sqlSessionFactory;
}
public ExecutorType getExecutorType() {
return this.executorType;
}
public PersistenceExceptionTranslator getPersistenceExceptionTranslator() {
return this.exceptionTranslator;
}
public <E> List<E> selectList(String statement) {
return this.sqlSessionProxy.selectList(statement);
}
public <E> List<E> selectList(String statement, Object parameter) {
return this.sqlSessionProxy.selectList(statement, parameter);
}
看的出来,这里面selectList()方法其实是调用的this.sqlSessionProxy,是一个代理类,而这个代理类就是在构造方法中定义的,就是this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor())
下面我们看一下这个代理类的执行方法,就是new SqlSessionTemplate.SqlSessionInterceptor()里面的invoke()方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取sqlSession对象
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.getSqlSession() 中去看看这个SqlSession 到底是什么东西。
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);
//如果SqlSessionHolder存在,则直接获取sqlSession
if (holder != null && holder.isSynchronizedWithTransaction()) {
if (holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
} else {
holder.requested();
if (logger.isDebugEnabled()) {
logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
}
return holder.getSqlSession();
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Creating a new SqlSession");
}
//这里是新创建一个SqlSession
SqlSession session = sessionFactory.openSession(executorType);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
if (logger.isDebugEnabled()) {
logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
}
//创建SqlSessionHolder
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
TransactionSynchronizationManager.registerSynchronization(new SqlSessionUtils.SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) != null) {
throw new TransientDataAccessResourceException("SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
}
}
} else if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
}
return session;
}
}
这里的sessionFactory是上面博客中创建的DefaultSqlSessionFactory,看一下里面的openSession()方法
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
DefaultSqlSession var8;
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException var13) {
autoCommit = true;
}
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var14, var14);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
return (TransactionFactory)(environment != null && environment.getTransactionFactory() != null ? environment.getTransactionFactory() : new ManagedTransactionFactory());
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException var3) {
;
}
}
}
}
可以看到openSession()调用了openSessionFromConnection()方法,里面创建了一个DefaultSqlSession对象。到这里我们已经获取了SqlSession对象,下一步看它实现的selestList()方法
/**
*这里面两个参数,第一个参数是mapper文件的命名空间+.+sql的id,第二个参数是我们的传参,第三个参数是分页的对象
**/
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var6;
try {
//我们通过这唯一的key去找到sql的定义类MappedStatement
MappedStatement ms = this.configuration.getMappedStatement(statement);
//这里通过相应的mybatis执行器去执行相应的sql
List<E> result = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
var6 = result;
} catch (Exception var10) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var10, var10);
} finally {
ErrorContext.instance().reset();
}
return var6;
}
通过跟踪代码可知 这个executor是SimpleExecutor,这里先不用关心怎么找到的SimpleExecutor,我们来看这个类里面的
query方法,这个类是继承的BaseExecutor,这个方法就在里面\
public abstract class BaseExecutor implements Executor {
...
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//boundSql 是sql的具体封装对象,里面有参数的定义,转化的sql语句和实际的传参
BoundSql boundSql = ms.getBoundSql(parameter);
//查找是否缓存
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//本文是没有缓存的,所以通过这个方法进行数据库的访问
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator i$ = this.deferredLoads.iterator();
while(i$.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)i$.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
...
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
这里面的doQuery()方法在它的子类SimpleExecutor中
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
//获取mybatis的配置类
Configuration configuration = ms.getConfiguration();
//获取StatementHandler,这个类的作用就是prepareStatement,
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = this.prepareStatement(handler, ms.getStatementLog());
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
我们来看一下configuration.newStatementHandler方法
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//这里实际上就生成的PreparedStatementHandler,
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//这里是根据配置的拦截器生成相应的代理类
StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
最后看一下handler.query()方法,也就是PreparedStatementHandler类中的query()方法
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
//可以看到底层也是通过jdbc进行数据库的访问的
ps.execute();
//这里通过myabtis的结果处理器,将ps返回的结果映射成我们定义的返回类型
return this.resultSetHandler.handleResultSets(ps);
}
这里的resultSetHandler默认是DefaultResultSetHandler
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
List<Object> multipleResults = new ArrayList();
int resultSetCount = 0;
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
this.validateResultMapsCount(rsw, resultMapCount);
while(rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
String[] resultSets = this.mappedStatement.getResulSets();
if (resultSets != null) {
while(rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
}
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
}
return this.collapseSingleResultList(multipleResults);
}
最后这个方法就是通过mybatis默认的resultHandler ,通过反射映射成我们定义的resultType 对象,并返回。
三、结束语
其实mybatis整体的流程主线并不复杂,就是将我们定义的mapper 文件进行解析,并封装成一个个的mapperStatment,执行sql的时候通过各种解析器,执行器转化为普通jdbc的Statement对象,然后通过resultHandler 对返回结果进行解析并返回。但是里面的细节很多,设计的类也有很多,所以有时间的话我们可以研究研究某一步的执行细节。