Mybatis-plus 源码执行全流程解析
废话 少数流程开始:
1、业务入口:userMapper.insertBatch(entityList);
执行到代理类: $Proxy222 (com.sun.proxy) 开始走代理流程,然后到了代理类:
idea 执行流程取出栈信息:
invoke:89, MybatisMapperProxy (com.baomidou.mybatisplus.core.override)
提前生成sqlSession ,地方如下:
2、代理类:public class MybatisMapperProxy<T> implements InvocationHandler, Serializable
// 当前代理类、方法名、保存的参数对象,可能多个
@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 {//核心接口进入,带着生成的sqlSession
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
来到:
// private final Map<Method, MapperMethodInvoker> methodCache; 类似缓存操作
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {// 集合的操作方法,通过接口回调返回数据
return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
if (m.isDefault()) {
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
进入新的invoke 方法:
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
//private final MybatisMapperMethod mapperMethod 方法名对象
return mapperMethod.execute(sqlSession, args);//核心操作
}
3、来到 public class MybatisMapperMethod 类:
// private final MapperMethod.MethodSignature method ;方法的类名
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {//MapperMethod.SqlCommand command; 对象
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);
// TODO 这里下面改了
if (IPage.class.isAssignableFrom(method.getReturnType())) {
result = executeForIPage(sqlSession, args);
// TODO 这里上面改了
} else {
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;
}
4、来到 public class MapperMethod 的内部类MethodSignature
//private final ParamNameResolver paramNameResolver; 参数分解器
public Object convertArgsToSqlCommandParam(Object[] args) {
return paramNameResolver.getNamedParams(args);//进入
}
5、来到:public class ParamNameResolver
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
Object value = args[names.firstKey()];
return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);
} else {
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, ...)
final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
最后返回:
下面重点分析:
result = rowCountResult(sqlSession.insert(command.getName(), param));
点击 sqlSession.insert(command.getName(), param) 进入:三个实现类的其中一个
根据上游入口判断进入spring的类:
public class SqlSessionTemplate implements SqlSession, DisposableBean
6、来到 SqlSessionTemplate
//private final SqlSession sqlSessionProxy;方法的全路径、执行参数
@Override
public int insert(String statement, Object parameter) {
return this.sqlSessionProxy.insert(statement, parameter);//进入
}
三个实现类:
来到子类 public class DefaultSqlSession implements SqlSession
7、DefaultSqlSession
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);//进入执行
}
来到:
//private final Executor executor;执行器接口
//private final Configuration configuration; 配置类
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);//创建声明,进入
return executor.update(ms, wrapCollection(parameter));//正式执行
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();//实例资源清除
}
}
点击configuration.getMappedStatement(statement) 进入
来到 public class MybatisConfiguration extends Configuration 此类为mybatisplus的类,继承的mybatis的配置类Configuration 。
8、MybatisConfiguration 类
//此id就是mapper的全路径,在此服务中应该也是唯一的值
@Override
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);//正式获取声明
}
来到:
//protected final Map<String, MappedStatement> mappedStatements
@Override
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();//上游传的true,进入
}
return mappedStatements.get(id);//在此处返回
}
点击: buildAllStatements() 进入父类Configuration,组装的细节后面我们会详细分享
protected void buildAllStatements() {
parsePendingResultMaps();
if (!incompleteCacheRefs.isEmpty()) {
synchronized (incompleteCacheRefs) {
incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
}
}
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) {
incompleteStatements.removeIf(x -> {
x.parseStatementNode();
return true;
});
}
}
if (!incompleteMethods.isEmpty()) {
synchronized (incompleteMethods) {
incompleteMethods.removeIf(x -> {
x.resolve();
return true;
});
}
}
}
返回后进入 executor.update(ms, wrapCollection(parameter));进入切面类
public class Plugin implements InvocationHandler
//切面方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
//private final Interceptor interceptor;拦截器接口
return interceptor.intercept(new Invocation(target, method, args));//进入拦截器
}
return method.invoke(target, args);//进行执行业务
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
点击:
来到:public class OptimisticLockerInterceptor implements Interceptor mybatis 中的类
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
if (SqlCommandType.UPDATE != ms.getSqlCommandType()) {
return invocation.proceed();
}
Object param = args[1];
if (param instanceof Map) {
Map map = (Map) param;
//updateById(et), update(et, wrapper);
Object et = map.getOrDefault(Constants.ENTITY, null);
if (et != null) {
// entity
String methodId = ms.getId();
String methodName = methodId.substring(methodId.lastIndexOf(StringPool.DOT) + 1);
TableInfo tableInfo = TableInfoHelper.getTableInfo(et.getClass());
if (tableInfo == null || !tableInfo.isWithVersion()) {
return invocation.proceed();
}
TableFieldInfo fieldInfo = tableInfo.getVersionFieldInfo();
Field versionField = fieldInfo.getField();
// 旧的 version 值
Object originalVersionVal = versionField.get(et);
if (originalVersionVal == null) {
return invocation.proceed();
}
String versionColumn = fieldInfo.getColumn();
// 新的 version 值
Object updatedVersionVal = this.getUpdatedVersionVal(fieldInfo.getPropertyType(), originalVersionVal);
if (PARAM_UPDATE_METHOD_NAME.equals(methodName)) {
AbstractWrapper<?, ?, ?> aw = (AbstractWrapper<?, ?, ?>) map.getOrDefault(Constants.WRAPPER, null);
if (aw == null) {
UpdateWrapper<?> uw = new UpdateWrapper<>();
uw.eq(versionColumn, originalVersionVal);
map.put(Constants.WRAPPER, uw);
} else {
aw.apply(versionColumn + " = {0}", originalVersionVal);
}
} else {
map.put(Constants.MP_OPTLOCK_VERSION_ORIGINAL, originalVersionVal);
}
versionField.set(et, updatedVersionVal);
return invocation.proceed();
}
}
return invocation.proceed();//点击进入
}
来到:public class Invocation
public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);//进入
}
到了:public final class Method extends Executable
@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
@HotSpotIntrinsicCandidate
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz,
Modifier.isStatic(modifiers) ? null : obj.getClass(),
modifiers);
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);//进入
}
进入:
三个实现类
9、来到 public class MybatisCachingExecutor implements Executor 实现类 mybatisplus包中
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);//刷新清除缓存,下次查询此表,会到数据库查,点击
// private final Executor delegate;执行器执行
return delegate.update(ms, parameterObject);//核心执行,点击
}
来到:
private void flushCacheIfRequired(MappedStatement ms) {
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
tcm.clear(cache);//清除缓存
}
}
点击 delegate.update(ms, parameterObject);
10、到了 public abstract class BaseExecutor implements Executor
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();//清除缓存
return doUpdate(ms, parameter);//正式执行
}
点击:
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
抽象方法的重写:有mybatis和plus的两组实现
10、 到:public class MybatisSimpleExecutor extends AbstractBaseExecutor
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);//生成执行的声明,里面很复杂,后期我们很专题讲解
stmt = prepareStatement(handler, ms.getStatementLog(), false);//拿数据源重点,进入
return stmt == null ? 0 : handler.update(stmt);//正式执行,点击
} finally {
closeStatement(stmt);//关闭声明
}
}
点击 prepareStatement(handler, ms.getStatementLog(), false);
private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isCursor) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);//取数据源,进入
stmt = handler.prepare(connection, transaction.getTimeout());封装数据源到声明里
//游标不支持返回null.
if (stmt == null && !isCursor) {
return null;
} else {
handler.parameterize(stmt);
return stmt;
}
}
11、到了父类 public abstract class BaseExecutor implements Executor
protected Connection getConnection(Log statementLog) throws SQLException {
// protected Transaction transaction;
Connection connection = transaction.getConnection();//获取数据源,进入
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
点击发现常用的三种实现:
显然 进入 mybatis-spring 包里的SpringManagedTransaction
10、来到 public class SpringManagedTransaction implements Transaction 类
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();//获取连接,进入
}
return this.connection;
}
点击 openConnection()
private void openConnection() throws SQLException {
//通过spring的工具类DataSourceUtils 获取 数据库连接connection(JDK包里的),进入
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();//自动提交的获取
//是否连接、事务的判断
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"
+ (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");
}
来到:
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);//点击
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
}
catch (IllegalStateException ex) {
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage());
}
}
点击:
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = fetchConnection(dataSource);//重点进入
if (TransactionSynchronizationManager.isSynchronizationActive()) {
try {
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
catch (RuntimeException ex) {
// Unexpected exception from external delegation call -> close Connection and rethrow.
releaseConnection(con, dataSource);
throw ex;
}
}
return con;
}
来到:
private static Connection fetchConnection(DataSource dataSource) throws SQLException {
Connection con = dataSource.getConnection();//点击进入,dataSource 的实现类
if (con == null) {
throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource);
}
return con;
}
点击:dataSource.getConnection()发现好的实现类,应该进入哪一个啊??
根据业务判断:进入NandaoDataSource
public class NandaoDataSource extends AbstractTenantDataSource implements DataSource, NandaoDataSourceMXBean, MBeanRegistration, AutoCloseable{
@Override
public Connection getConnection() throws SQLException {
if (provider == null) {
throw new Exception("provider is null");
}
return getConnection(provider.getUserId());//业务封装回去自定义数据源
}
进入
public Connection getConnection(String userId) throws SQLException {
for (int retry = 1; retry <= retryTimes; retry++) {
UserDbInfo dbInfo = userDbInfoInfoService.getDatabaseInfo(userId);
return getDataSource(dbInfo).getConnection();
}
}
这是获取数据源的流程,分析到此,下篇我们分析真正执行数据库的流程 handler.update(stmt);,敬请期待!