文章目录
参考:
深入浅出Mybatis系列(十)—SQL执行流程分析(源码篇)
MyBatis源码解析(二)——动态代理实现函数调用
Mybatis运行原理及源码解析
一.SqlSession的创建(OpenSession)
- Mybatis通过DefaultSqlSessionFactory类来创建SqlSession.
- 这个类包含Configration对象,即包含Mybatis初始化的所有元素
- 打开sqlSession的同时设置事务、执行器等信息.
从DefaultSqlSessionFactory中打开sqlsession
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
//30.1 这边打开了SqlSession
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
.........
}
设置参数、环境,返回DefaultSqlSession对象
//30.1
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//30.1 拿到配置的环境信息
final Environment environment = configuration.getEnvironment();
//30.1 拿到事务
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//30.1 创建新的Executor执行器
final Executor executor = configuration.newExecutor(tx, execType);
//30.1 构造。返回DefaultSqlSession
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();
}
}
二.从Configration中获取接口对应代理类MapperProxy
拿到SqlSession以后我们还需要拿到对应的接口实现类,这边是通过MapperProxy去代理生成对应类,接下来就是查找MapperProxy类的过程
去configration中查找
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
configration从MapperRegister的knowMappers中得到初始化完成的类并代理生成实例返回
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//通过类型得到对应的代理类
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//代理方式初始化类
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
三.MapperProxy的执行
1.先调用MapperProxy的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
//这个方法决定执行sqlSession中的CRUD的哪个方法
return mapperMethod.execute(sqlSession, args);
}
2.通过MapperMethod的execute方法判断执行sqlSession的哪个CRUD方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
四.简述selectList
方便起见我们拿selectList这个方法出来看
1.获取MappedStatement
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//从configration中 根据类名 获取我们初始化好的 MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
//执行缓存查询或者是sql查询
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();
}
}
2.Executor的执行
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//....................略
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
//................略
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//................略
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
//.......................略
return list;
}
3.最原始的statement构建和数据库连接操作
//经过一些列的构造之后,终于进入了最原始的statement构建和数据库连接操作
@Override
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.查询结果ResultSet处理
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}
5.处理ResultMap或者ResultSet
这一块的处理类似把sql查询的结果行拿回来自己解析,具体解析方法不展开.
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
//.......略
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
//......略
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
//.........略
handleResultSet(rsw, resultMap, null, parentMapping);
}
}
//返回结果
return collapseSingleResultList(multipleResults);
}
五.时序图
参考:时序图