勿以浮沙筑高台
config解析过程见文章:
Mybatis源码解析(一)newconfiguration构造过程
mapper-resultmap解析过程见文章:
Mybatis源码解析(二)mapper-resultmap详解构造过程
mapper-sql解析过程见文章:
Mybatis源码解析(三)mapper-sql详解构造过程
在上一章中我们主要解析了sql语句的拼接过程:
1.他会去寻找对应sql中的body
2.通过元素标签,找到对应的sqlcommandtype的类型
3.解析元素标签的body,判断有没有${}这样的标识符,如果有则是动态语句,需要进行替换。
4.判断完成后递归解析include的标签,将include的内容替换掉。
5.开始截取字符串#{opentoken之前的拼接为sql,中间参数生成参数解析器对象。在元sql中拼接?问号占位符。
6.将sql,express,config封装为sqlsource资源对象进行返回。
前面三章我们就解析完成了sqlSource的解析了。也就是我们调用时的build的这2句
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
下面我们解析,session会话的创建过程。
session = sqlSessionFactory.openSession();
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
//从configuration中拿到整个环境
Environment environment = this.configuration.getEnvironment();
//拿到事务工厂
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
//传入数据源,隔离级别,自动提交
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//执行器对象
//链接:AH-01
Executor executor = this.configuration.newExecutor(tx, execType);
//返回一个默认的Session
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
AH-01:org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)
//transaction:事务
//executorType:传入一个简单执行器的类型
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
//判断类型为空不,不为空就是自己设定的类型
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
//上面传入的simple简单对象,走这里。
//构建一个简单的执行器对象
//链接:AH-02
executor = new SimpleExecutor(this, transaction);
}
//判断是否开启了缓存对象
if (this.cacheEnabled) {
//如果开启了缓存对象,构建一个缓存对象
//装饰器模式,将simple装饰为caching
executor = new CachingExecutor((Executor)executor);
}
//拦截器链
//对插件的支持
//如果有则要调用pulgin方法
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
//将包装好的executor返回
//return AH-01
return executor;
}
AH-02:org.apache.ibatis.executor.SimpleExecutor#SimpleExecutor
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
protected BaseExecutor(Configuration configuration, Transaction transaction) {
this.transaction = transaction;
//新建缓存
this.deferredLoads = new ConcurrentLinkedQueue();
//新建缓存ID为LocalCache
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
//将config保存起来
this.configuration = configuration;
//将当前simpleexecuter存入进去
this.wrapper = this;
//return AH-02
}
上面执行器就封装完成了。
下面就是调用
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectAll();
users.forEach(u-> System.out.println(u.getUserName()));
org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
org.apache.ibatis.session.Configuration#getMapper
//sqlSession:默认的简单执行器
//type:userclass
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
org.apache.ibatis.binding.MapperRegistry#getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//通过type拿到工厂对象
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//通过实例化的方式将执行器注入工厂对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)
public T newInstance(SqlSession sqlSession) {
//sqlsession,执行器对象
//mapperInterface:我们的命名空间
//methodCache:null
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
//链接:AH-01
return this.newInstance(mapperProxy);
}
org.apache.ibatis.binding.MapperProxy#MapperProxy
//构建MapperProxy对象
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
AH-01:org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.binding.MapperProxy<T>)
protected T newInstance(MapperProxy<T> mapperProxy) {
//创建动态代理对象
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
上面我们就拿到了代理对象。
下面就是调用代理对象中的方法。
List<User> users = mapper.selectAll();
org.apache.ibatis.binding.MapperProxy#invoke
//他会回调代理类中的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//判断当前的类是不是Object类
if (Object.class.equals(method.getDeclaringClass())) {
//如果是object的类则不需要处理,直接调用invoke,当前实际方法
return method.invoke(this, args);
}
//如果不属于object的类但是是接口中的默认方法
if (this.isDefaultMethod(method)) {
//则直接调用默认方法
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
//判断缓存里有没有我需要的方法,没有则创建缓存,有则直接拿取
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//执行方法
return mapperMethod.execute(this.sqlSession, args);
}
isDefaultMethod:org.apache.ibatis.binding.MapperProxy#isDefaultMethod
private boolean isDefaultMethod(Method method) {
//判断当前类是不是public默认方法所在类的是不是接口
return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
}
cachedMapperMethod:org.apache.ibatis.binding.MapperProxy#cachedMapperMethod
private MapperMethod cachedMapperMethod(Method method) {
//将你的方法缓存起来
return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
});
}
execute:org.apache.ibatis.binding.MapperMethod#execute
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
//判断当前执行指令的类型
switch(this.command.getType()) {
//增
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
//判断你的返回值是不是空,是不是又结果的处理器
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
}
//是否返回List集合
else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
}
//是否返回map
else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
}
else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
}
else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
executeForMany:``
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
Object param = this.method.convertArgsToSqlCommandParam(args);
List result;
//判断方法是否分页
if (this.method.hasRowBounds()) {
//查询的行信息
RowBounds rowBounds = this.method.extractRowBounds(args);
//执行命令,把名称,参数,行信息传进去
result = sqlSession.selectList(this.command.getName(), param, rowBounds);
} else {
//执行命令,把名称,参数,传进去
result = sqlSession.selectList(this.command.getName(), param);
}
if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
} else {
return result;
}
}
query:org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement);
//使用执行器去执行我们的方法
//链接:AH-02
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
wrapCollection:org.apache.ibatis.session.defaults.DefaultSqlSession#wrapCollection
private Object wrapCollection(Object object) {
DefaultSqlSession.StrictMap map;
//如果参数是集合则包装为集合
if (object instanceof Collection) {
map = new DefaultSqlSession.StrictMap();
map.put("collection", object);
//如果参数list则包装为list
if (object instanceof List) {
map.put("list", object);
}
return map;
}
//如果参数是数组则包装为一个数组
else if (object != null && object.getClass().isArray()) {
map = new DefaultSqlSession.StrictMap();
map.put("array", object);
return map;
} else {
return object;
}
}
AH-03:``
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//参数绑定方法
BoundSql boundSql = ms.getBoundSql(parameterObject);
//将请求参数组装起来,成为一个唯一的key
CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
//执行查询方法
//链接:AH-04
return this.query(ms, parameterObject, rowBounds, resultHandler, key,
boundSql);
//return AH-03
}
AH-04:org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
//判断有没有缓存
if (cache != null) {
this.flushCacheIfRequired(ms);
//判断
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, boundSql);
List<E> list = (List)this.tcm.getObject(cache, key);
if (list == null) {
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
}
return list;
}
}
//没有缓存则直接用代理的目标类query方法
//链接:AH-05
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
//return AH-04
}
AH-05:org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.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 {
//缓存里面没有值则从数据库中拿取
//链接:AH-06
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
AH-06:org.apache.ibatis.executor.BaseExecutor#queryFromDatabase
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//将key和一个枚举做关联
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//开始真正执行查询语句
//链接:AH-07
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;
}
AH-07:``
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
//拿到configuration
Configuration configuration = ms.getConfiguration();
//创建一个编译预处理器对象
//链接:AH-08
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//链接:AH-09
stmt = this.prepareStatement(handler, ms.getStatementLog());
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
AH-08:``
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据你们执行器找到对应的编译处理器
//将执行器,参数,别名,注册工程都保留起来
//并构件2个处理器,一个是请求参数处理器,一个是返回结果处理器
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//执行拦截节器插件
StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
//return AH-08
return statementHandler;
}
AH-09:org.apache.ibatis.executor.SimpleExecutor#prepareStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
//得到一个链接对象
Connection connection = this.getConnection(statementLog);
//得到链接对象后,通过处理器执行
//链接:AH-10
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
//对编译好的语句进行参数化处理
//链接:AH-12
handler.parameterize(stmt);
return stmt;
}
AH-10:org.apache.ibatis.executor.statement.BaseStatementHandler#prepare
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(this.boundSql.getSql());
Statement statement = null;
try {
//拿到Sql语句
//编译sql语句
//链接:AH-11
statement = this.instantiateStatement(connection);
//设置事务的超时时间
this.setStatementTimeout(statement, transactionTimeout);
//拉去的数据条数
this.setFetchSize(statement);
//return AH-10
return statement;
} catch (SQLException var5) {
this.closeStatement(statement);
throw var5;
} catch (Exception var6) {
this.closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + var6, var6);
}
}
AH-11:org.apache.ibatis.executor.statement.PreparedStatementHandler#instantiateStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
//拿到sql语句
String sql = this.boundSql.getSql();
//判断对应的数据有没有需要自动增长
if (this.mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = this.mappedStatement.getKeyColumns();
return keyColumnNames == null ? connection.prepareStatement(sql, 1) : connection.prepareStatement(sql, keyColumnNames);
} else {
//没有的话直接编译sql语句
//connection.prepareStatement(sql)
return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.prepareStatement(sql) : connection.prepareStatement(sql, this.mappedStatement.getResultSetType().getValue(), 1007);
}
//return AH
}
AH-12:org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
//得到你的参数映射集合
List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
if (parameterMappings != null) {
for(int i = 0; i < parameterMappings.size(); ++i) {
//将你的映射参数拿出来
ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
//判断是不是输出参数
if (parameterMapping.getMode() != ParameterMode.OUT) {
//如果是输出参数则拿到你的name
String propertyName = parameterMapping.getProperty();
Object value;
if (this.boundSql.hasAdditionalParameter(propertyName)) {
value = this.boundSql.getAdditionalParameter(propertyName);
} else if (this.parameterObject == null) {
value = null;
} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
value = this.parameterObject;
} else {
MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
value = metaObject.getValue(propertyName);
}
//类型处理器对象
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
//设置为空
jdbcType = this.configuration.getJdbcTypeForNull();
}
try {
//通过类型找到你对应的参数处理器编译
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException var10) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
} catch (SQLException var11) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);
}
}
}
}
至此,mybatis从解析配置文件到sql拼接到编译过程全部完成