文章目录
前言
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(new FileInputStream(""));
SqlSession sqlSession = factory.openSession();
EmpHistoryMapper mapper = sqlSession.getMapper(EmpHistoryMapper.class);
mapper.findHistoryEmployeeInfoById(1);
Mybais的使用流程大致如上,按如上代码逐步分析
一、SqlSessionFactoryBuilder
解析xml,实例化SessionFactory
1、build
解析XML为Cofiguration
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 解析XML为Document
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 将Document解析为Configuration
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
// 实例化DefaultSqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
二、XMLConfigBuilder
解析Document为Configuration
1、parse
public Configuration parse() {
// 如果已经解析过,抛出异常
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 从configuration节点开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
2、parseConfiguration
解析configuration节点
try {
//解析properties节点,并设置到configuration得variables属性
propertiesElement(root.evalNode("properties"));
//解析setting节点,setting节点用来设置configuration属性,如果setting的属性是configuration没有的属性,则会抛出异常
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 设置configuration的vfsImpl
loadCustomVfs(settings);
// 设置configuration的logImpl-自定义日志实现
loadCustomLogImpl(settings);
// 解析typeAliases节点,如果为packeage,则扫描这个包下所有的累,并注册为(类简单名称-class.simpleName,class)到typeAliasRegistry,如果是type,alias,则直接注册
typeAliasesElement(root.evalNode("typeAliases"));
// 解析plugins节点,并添加到configuration的interceptors
pluginElement(root.evalNode("plugins"));
// 解析objectFactory节点,实例化并设置到configuration的objectFacotry,objectFactory用来将查询的数据转为ResutlDTO。
objectFactoryElement(root.evalNode("objectFactory"));
// 解析objectWrapperFactory节点,实例化并设置到configuration的objectWrapperFactory
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析reflectorFactory节点,实例化并设置到configuration的reflectorFactory
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 将settings节点的内容设置到configuration,如果settings没有的属性,则设置默认值
settingsElement(settings);
// 解析environments节点,将节点的datasource和transactionManager封装为Enviroment并设置到configuration的environment属性
environmentsElement(root.evalNode("environments"));
// 解析databaseIdProvider节点,并设置configuration的databaseid为自定义获取的数据库名称
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 处理typeHandlers节点,结果字段类型转换处理器
typeHandlerElement(root.evalNode("typeHandlers"));
// 处理mapper节点
// 1、如果为package类型,则扫描package下的接口生产代理工厂MapperProxyFactory放入到knownMappers,并查找是否有对应的xml,有则解析xml的resultMap,mappedStatement
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
三、DefaultSqlSessionFactory
1、openSession
实例化Session
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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);
// 获取simple类型执行器
final Executor executor = configuration.newExecutor(tx, execType);
// 实例化Session
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();
}
}
// 实例化Exexecutor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 如果允许使用缓存,则由CachingExecutor封装SimpleExecutor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 将所有plugin封装倒executor
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
2、getMapper
从kownMapper(前面parseConfiguration解析mapper节点),用全类名获取MapperProxyFactory,由代理工厂创建代理对象MapperProxy
// 获取代理对象
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
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);
}
}
// 实例化代理对象
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
// JDK反向代理
return newInstance(mapperProxy);
}
四、MapperProxy
由于getMapper返回了代理对象,继而执行mapper.findHistoryEmployeeInfoById()方法时会有MapperProxy代理执行
1、invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 对象类型为object类型,直接原方法执行
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
// 如果改方法是public非static,非抽象(有方法body)得接口方法即为default修饰的方法,jdk代理执行
} else if (method.isDefault()) {
if (privateLookupInMethod == null) {
return invokeDefaultMethodJava8(proxy, method, args);
} else {
return invokeDefaultMethodJava9(proxy, method, args);
}
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 实例化MapperMethod
final MapperMethod mapperMethod = cachedMapperMethod(method);
//
return mapperMethod.execute(sqlSession, args);
}
// 尝试从缓存中获取MapperMethod,没有则实例化MapperMethod
private MapperMethod cachedMapperMethod(Method method) {
return methodCache.computeIfAbsent(method,
k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
// 实例化MapperMethod
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
// 实例化SqlCommand
this.command = new SqlCommand(config, mapperInterface, method);
// 实例化MethodSignature
this.method = new MethodSignature(config, mapperInterface, method);
}
// 实例化SqlCommand
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
// 根据全类名.方法名从Configuration获取MappedStatement
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
//获取不到MappedStatement
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
// 抛出找不到statement得异常
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
// 设置name和type
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
// 实例化MethodSignature 方法签名
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 返回类型--处理泛型、数组元素类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
// 返回类型是否void
this.returnsVoid = void.class.equals(this.returnType);
// 返回类型是否集合
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
// 返回类型是否Cursor
this.returnsCursor = Cursor.class.equals(this.returnType);
// 返回类型是否Optional
this.returnsOptional = Optional.class.equals(this.returnType);
// 解析MapKey注解
this.mapKey = getMapKey(method);
// 是否有returnsMap
this.returnsMap = this.mapKey != null;
// 获取类型为RowBounds得参数得索引下标--Page实现了RowBounds
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
// 获取类型为ResultHandler得参数得索引下标
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// 实例化ParamNameResolver
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
// 实例化ParamNameResolver
public ParamNameResolver(Configuration config, Method method) {
// 获取方法所有参数类型
final Class<?>[] paramTypes = method.getParameterTypes();
// 获取方法所有参数注解
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
// 参数个数
int paramCount = paramAnnotations.length;
// get names from @Param annotations-处理被@Param注解得参数
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
// 跳过RowBounds和ResultHandler
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
// 遍历所有注解
for (Annotation annotation : paramAnnotations[paramIndex]) {
// 注解为Param
if (annotation instanceof Param) {
// 标记hasParamAnnotation为true
hasParamAnnotation = true;
// 设置name为Param的value,参数名称
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified. -- 设置name获取参数名称
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// 设置为当前map大小
// gcode issue #71
name = String.valueOf(map.size());
}
}
// map<参数索引,参数名称> name可能为Param的value,方法参数名称,数字
map.put(paramIndex, name);
}
// names <参数索引,参数名称>
names = Collections.unmodifiableSortedMap(map);
}
五、MapperMethod
1、execute
解析执行sql
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
.....
// select语句,以下只分析executeForMany
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) { // 返回结果为集合
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {// 返回结果为Map
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
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;
}
// 处理返回类型为集合的sql
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
// 封装参数<select>中的变量#{name}
Object param = method.convertArgsToSqlCommandParam(args);
// 参数是否RowBounds-Page
if (method.hasRowBounds()) {
// 获取参数RowBounds
RowBounds rowBounds = method.extractRowBounds(args);
// 准备执行查询
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
result = sqlSession.selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
// 封装参数<select>中的变量#{name}
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);
}
public Object getNamedParams(Object[] args) {
// 参数个数,可以被<select>中的变量#{name}使用的参数个数
final int paramCount = names.size();
// 无参
if (args == null || paramCount == 0) {
return null;
// 有Param注解的参数并且参数个数为一个
} else if (!hasParamAnnotation && paramCount == 1) {
// 直接返回第一个参数
return args[names.firstKey()];
} else {
// 实例化参数Map<参数名称,值> 参数名称name可能为Param的value,方法参数名称,数字,或者param1(2.3)
final Map<String, Object> param = new ParamMap<>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
// 参数名称,参数值
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
// 另一套键值对 param1 , value
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
// 判断names是否已经有 param1,确保不覆盖@Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
六、DefaultSqlSession
会话
1、selectList
执行返回结果为集合的查询
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 获取对应的MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
// 由Executor执行查询,这一块本身有缓存的话Executor会被CachingExecutor封装,由于基本不开启缓存,所以从SimpleExecutor分析
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();
}
}
// 处理只有一个参数类型为集合并且没有@Param的情
// Collection <list, value>
// Array <array, value>
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<>();
map.put("array", object);
return map;
}
return object;
}
// 执行查询,返回结果
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 解析xml标签,解析sql封装为BoundSql
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 开始查询
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
// 解析xml标签,解析sql封装为BoundSql
public BoundSql getBoundSql(Object parameterObject) {
// sqlSource在处理mappedStatement时实例化,有标签情况下其实现类为BoundSql
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
// 获取BoundsQL
public BoundSql getBoundSql(Object parameterObject) {
// 上下文
DynamicContext context = new DynamicContext(configuration, parameterObject);
// rootSql在解析MapperStatement(XMLStatementBuilder)处理过程中解析标签后实例化,其实现类为MixedSqlNode,内部包含各种具体标签类,由XMLScriptBuilder解析处理Xml Node为Mybatis Node(NodeHandler->ForEachSqlNode/IfSqlNode)
// 此处解析各种标签和处理${}
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
// 处理#{}为?,返回StaticSqlSource
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
}
2、query
执行查询
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 (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
// 尝试从缓存拿
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 从数据库查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
// 从数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// 由Handler执行查询,并处理返回结果
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}