Mybatis

Mybatis

1.     Source

1.1 Version

1.2 Introduce

2.     Session

2.1 SqlSessionManager

2.2 SqlSession

2.3 DefaultSqlSession

2.4 SqlSessionFactory

3.     Executor

3.1 Executor

3.2 BaseExecutor

3.3 CachingExecutor

4.     Handler

4.1 StatementHandler

4.2 ParameterHandler

4.3 ResultHandler

5.     cache

5.1 cache

5.2 CacheKey

5.3 TransactionalCacheManager

5.4 CachingExecutor

6.     reflection

6.1 Invoker

6.2 Reflector

7.     binding

7.1 MapperProxy

7.2 MapperMethod

8.     mapping

8.1 BoundSql

8.2 MappedStatement

8.3 ParameterMapping

8.4 ResultMapping

9.     参考文献

 

1.    Source

 

1.1 Version

Versionmybatis-3.5.2-sources

1.2 Introduce

整体流程图

IMG_256

 

2.    Session

2.1  SqlSessionManager

org.apache.ibatis.session. SqlSessionManager的主要属性

 

public class SqlSessionManager implements SqlSessionFactory, SqlSession {

  private final SqlSessionFactory sqlSessionFactory;

  private final SqlSession sqlSessionProxy;

  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();

  private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {

    this.sqlSessionFactory = sqlSessionFactory;

    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(

        SqlSessionFactory.class.getClassLoader(),

        new Class[]{SqlSession.class},

        new SqlSessionInterceptor());

  }

}

 

org.apache.ibatis.session. SqlSessionManager的事务提交,关闭等

 

 

@Override

  public void commit(boolean force) {

    final SqlSession sqlSession = localSqlSession.get();

    if (sqlSession == null) {

      throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");

    }

    sqlSession.commit(force);

  }

 

  @Override

  public void rollback() {

    final SqlSession sqlSession = localSqlSession.get();

    if (sqlSession == null) {

      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");

    }

    sqlSession.rollback();

  }

 

 

 

2.2 SqlSession

org.apache.ibatis.session. SqlSession的主要方法

public interface SqlSession extends Closeable {

  <T> T selectOne(String statement);

<T> T selectOne(String statement, Object parameter);

  int insert(String statement);

}

 

2.3 DefaultSqlSession

org.apache.ibatis.session.defaults.DefaultSqlSession的执行性流程,selectList案例

@Override

  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {

    try {

      MappedStatement ms = configuration.getMappedStatement(statement);

      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.4 SqlSessionFactory

org.apache.ibatis.session. SqlSessionFactory的主要方法

 

 

public interface SqlSessionFactory {

 

  SqlSession openSession();

 

  SqlSession openSession(boolean autoCommit);

 

  SqlSession openSession(Connection connection);

 

  SqlSession openSession(TransactionIsolationLevel level);

 

  SqlSession openSession(ExecutorType execType);

 

  SqlSession openSession(ExecutorType execType, boolean autoCommit);

 

  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);

 

  SqlSession openSession(ExecutorType execType, Connection connection);

 

  Configuration getConfiguration();

 

}

 

org.apache.ibatis.session.defaults. DefaultSqlSessionFactory的获取SqlSession的方法

 

  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);

      final Executor executor = configuration.newExecutor(tx, execType);

      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();

    }

  }

 

 

3.    Executor

3.1 Executor

org.apache.ibatis.executor. Executor的主要方法

 

public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  int update(MappedStatement ms, Object parameter) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  List<BatchResult> flushStatements() throws SQLException;

  void commit(boolean required) throws SQLException;

  void rollback(boolean required) throws SQLException;

  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  boolean isCached(MappedStatement ms, CacheKey key);

  void clearLocalCache();

  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

  Transaction getTransaction();

  void close(boolean forceRollback);

  boolean isClosed();

  void setExecutorWrapper(Executor executor);

}

 

3.2 BaseExecutor

org.apache.ibatis.executor. BaseExecutor的模板方法

 

 

protected abstract int doUpdate(MappedStatement ms, Object parameter)

      throws SQLException;

  protected abstract List<BatchResult> doFlushStatements(boolean isRollback)

      throws SQLException;

  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)

      throws SQLException;

  protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)

      throws SQLException;

 

 

3.2.1 SimpleExecutor

org.apache.ibatis.executor. SimpleExecutor的通过StatementHandler实现

 

 

  @Override

  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);

    }

  }

 

 

3.2.2 ReuseExecutor

 

org.apache.ibatis.executor. ReuseExecutor的通过prepareStatement复用Statement

 

 

  private final Map<String, Statement> statementMap = new HashMap<>();

 

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

    Statement stmt;

    BoundSql boundSql = handler.getBoundSql();

    String sql = boundSql.getSql();

    if (hasStatementFor(sql)) {

      stmt = getStatement(sql);

      applyTransactionTimeout(stmt);

    } else {

      Connection connection = getConnection(statementLog);

      stmt = handler.prepare(connection, transaction.getTimeout());

      putStatement(sql, stmt);

    }

    handler.parameterize(stmt);

    return stmt;

  }

 

  private boolean hasStatementFor(String sql) {

    try {

      return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();

    } catch (SQLException e) {

      return false;

    }

  }

 

 

 

 

3.2.3 BatchExecutor(待补充)

 

--todo

 

 

 

3.2.4 ClosedExecutor

org.apache.ibatis.executor.loader. ResultLoaderMap. ClosedExecutorResultLoaderMap使用

  private static final class ClosedExecutor extends BaseExecutor {

 

    public ClosedExecutor() {

      super(null, null);

    }

 

    @Override

    public boolean isClosed() {

      return true;

    }

 

3.3 CachingExecutor

org.apache.ibatis.executor. CachingExecutor是使用TransactionalCacheManagerCacheKey

 

 

public class CachingExecutor implements Executor {

 

  private final Executor delegate;

  private final TransactionalCacheManager tcm = new TransactionalCacheManager();

 

  public CachingExecutor(Executor delegate) {

    this.delegate = delegate;

    delegate.setExecutorWrapper(this);

  }

}

 

 

org.apache.ibatis.cache.TransactionalCacheManager 使用Map作为缓存

 

 

public class TransactionalCacheManager {

  private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>();

}

 

 

 

org.apache.ibatis.executor. CachingExecutor是使用query 方法

  @Override

  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) {

      flushCacheIfRequired(ms);

      if (ms.isUseCache() && resultHandler == null) {

        ensureNoOutParams(ms, boundSql);

        @SuppressWarnings("unchecked")

        List<E> list = (List<E>) tcm.getObject(cache, key);

        if (list == null) {

          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

          tcm.putObject(cache, key, list); // issue #578 and #116

        }

        return list;

      }

    }

    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

  }

 

 

4.    Handler

4.1 StatementHandler

 

org.apache.ibatis.executor.statementStatementHandler是主要方法

 

public interface StatementHandler {

 

  Statement prepare(Connection connection, Integer transactionTimeout)

      throws SQLException;

 

  void parameterize(Statement statement)

      throws SQLException;

 

  void batch(Statement statement)

      throws SQLException;

 

  int update(Statement statement)

      throws SQLException;

 

  <E> List<E> query(Statement statement, ResultHandler resultHandler)

      throws SQLException;

 

  <E> Cursor<E> queryCursor(Statement statement)

      throws SQLException;

 

  BoundSql getBoundSql();

 

  ParameterHandler getParameterHandler();

 

}

 

 

 

4.1.1 RoutingStatementHandler

org.apache.ibatis.executor.statement.RoutingStatementHandler是构造方法

 

public class RoutingStatementHandler implements StatementHandler {

 

  private final StatementHandler delegate;

 

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

 

    switch (ms.getStatementType()) {

      case STATEMENT:

        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);

        break;

      case PREPARED:

        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);

        break;

      case CALLABLE:

        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);

        break;

      default:

        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());

    }

 

  }

 

 

4.1.2 BaseStatementHandler

org.apache.ibatis.executor.statement. BaseStatementHandler是基本属性

 

 

public abstract class BaseStatementHandler implements StatementHandler {

 

  protected final Configuration configuration;

  protected final ObjectFactory objectFactory;

  protected final TypeHandlerRegistry typeHandlerRegistry;

  protected final ResultSetHandler resultSetHandler;

  protected final ParameterHandler parameterHandler;

 

  protected final Executor executor;

  protected final MappedStatement mappedStatement;

  protected final RowBounds rowBounds;

 

  protected BoundSql boundSql;

 

  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    this.configuration = mappedStatement.getConfiguration();

    this.executor = executor;

    this.mappedStatement = mappedStatement;

    this.rowBounds = rowBounds;

 

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();

    this.objectFactory = configuration.getObjectFactory();

 

    if (boundSql == null) { // issue #435, get the key before calculating the statement

      generateKeys(parameterObject);

      boundSql = mappedStatement.getBoundSql(parameterObject);

    }

 

    this.boundSql = boundSql;

 

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);

    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);

  }

 

 

4.1.3 SimpleStatementHandler

org.apache.ibatis.executor.statement. SimpleStatementHandler的使用java.sql.Statement

 

public class SimpleStatementHandler extends BaseStatementHandler {

 

  public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);

  }

 

  @Override

  public int update(Statement statement) throws SQLException {

    String sql = boundSql.getSql();

    Object parameterObject = boundSql.getParameterObject();

    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();

    int rows;

    if (keyGenerator instanceof Jdbc3KeyGenerator) {

      statement.execute(sql, Statement.RETURN_GENERATED_KEYS);

      rows = statement.getUpdateCount();

      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);

    } else if (keyGenerator instanceof SelectKeyGenerator) {

      statement.execute(sql);

      rows = statement.getUpdateCount();

      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);

    } else {

      statement.execute(sql);

      rows = statement.getUpdateCount();

    }

    return rows;

  }

 

4.1.4 PreparedStatementHandler

org.apache.ibatis.executor.statement. PreparedStatementHandler的使用java.sql. PreparedStatement

 

public class PreparedStatementHandler extends BaseStatementHandler {

 

  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);

  }

 

  @Override

  public int update(Statement statement) throws SQLException {

    PreparedStatement ps = (PreparedStatement) statement;

    ps.execute();

    int rows = ps.getUpdateCount();

    Object parameterObject = boundSql.getParameterObject();

    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();

    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);

    return rows;

  }

}

 

4.1.5 CallableStatementHandler

org.apache.ibatis.executor.statement. CallableStatementHandler的使用java.sql. CallableStatement

 

public class CallableStatementHandler extends BaseStatementHandler {

 

  public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);

  }

 

  @Override

  public int update(Statement statement) throws SQLException {

    CallableStatement cs = (CallableStatement) statement;

    cs.execute();

    int rows = cs.getUpdateCount();

    Object parameterObject = boundSql.getParameterObject();

    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();

    keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);

    resultSetHandler.handleOutputParameters(cs);

    return rows;

  }

}

 

 

 

 

4.2 ParameterHandler

 

 

org.apache.ibatis.scripting.defaults. DefaultParameterHandler的處理ParameterMapping

 

 

 

@Override

  public void setParameters(PreparedStatement ps) {

    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());

    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

    if (parameterMappings != null) {

      for (int i = 0; i < parameterMappings.size(); i++) {

        ParameterMapping parameterMapping = parameterMappings.get(i);

        if (parameterMapping.getMode() != ParameterMode.OUT) {

          Object value;

          String propertyName = parameterMapping.getProperty();

          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params

            value = boundSql.getAdditionalParameter(propertyName);

          } else if (parameterObject == null) {

            value = null;

          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

            value = parameterObject;

          } else {

            MetaObject metaObject = configuration.newMetaObject(parameterObject);

            value = metaObject.getValue(propertyName);

          }

          TypeHandler typeHandler = parameterMapping.getTypeHandler();

          JdbcType jdbcType = parameterMapping.getJdbcType();

          if (value == null && jdbcType == null) {

            jdbcType = configuration.getJdbcTypeForNull();

          }

          try {

            typeHandler.setParameter(ps, i + 1, value, jdbcType);

          } catch (TypeException | SQLException e) {

            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);

          }

        }

      }

    }

  }

 

4.3 ResultHandler

 

org.apache.ibatis.session. ResultHandler方法

 

public interface ResultHandler<T> {

 

  void handleResult(ResultContext<? extends T> resultContext);

 

}

 

 

org.apache.ibatis.executor.result. DefaultMapResultHandler反射出result對象

 

 

 

public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {

 

  private final Map<K, V> mappedResults;

  private final String mapKey;

  private final ObjectFactory objectFactory;

  private final ObjectWrapperFactory objectWrapperFactory;

  private final ReflectorFactory reflectorFactory;

 

  @SuppressWarnings("unchecked")

  public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {

    this.objectFactory = objectFactory;

    this.objectWrapperFactory = objectWrapperFactory;

    this.reflectorFactory = reflectorFactory;

    this.mappedResults = objectFactory.create(Map.class);

    this.mapKey = mapKey;

  }

 

  @Override

  public void handleResult(ResultContext<? extends V> context) {

    final V value = context.getResultObject();

    final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);

    // TODO is that assignment always true?

    final K key = (K) mo.getValue(mapKey);

    mappedResults.put(key, value);

  }

 

org.apache.ibatis.session.defaults. DefaultSqlSession示例selectMap

 

  @Override

  public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {

    final List<? extends V> list = selectList(statement, parameter, rowBounds);

    final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,

            configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());

    final DefaultResultContext<V> context = new DefaultResultContext<>();

    for (V o : list) {

      context.nextResultObject(o);

      mapResultHandler.handleResult(context);

    }

    return mapResultHandler.getMappedResults();

  }

 

 

5.    cache

5.1 cache

Mybatis缓存机制ss

 

public interface Cache {

  String getId();

  void putObject(Object key, Object value);

  Object getObject(Object key);

  Object removeObject(Object key);

  void clear();

  int getSize();

  default ReadWriteLock getReadWriteLock() {

    return null;

  }

 

}

 

5.2 CacheKey

org.apache.ibatis.cache .CacheKey内容

private List<Object> updateList;

  public CacheKey() {

    this.hashcode = DEFAULT_HASHCODE;

    this.multiplier = DEFAULT_MULTIPLYER;

    this.count = 0;

    this.updateList = new ArrayList<>();

  }

 

 

5.3 TransactionalCacheManager

 

 

org.apache.ibatis.cache.TransactionalCacheManager 使用Map作为缓存

 

public class TransactionalCacheManager {

  private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>();

}

 

 

 

5.4  CachingExecutor

 

org.apache.ibatis.session. Configuration配置中cacheEnabled存在时候开始使用二级缓存

 

 

 

 

  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);

    }

    if (cacheEnabled) {

      executor = new CachingExecutor(executor);

    }

    executor = (Executor) interceptorChain.pluginAll(executor);

    return executor;

  }

 

org.apache.ibatis.executor. CachingExecutor是缓存使用二级缓存》一级缓存

  @Override

  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) {

      flushCacheIfRequired(ms);

      if (ms.isUseCache() && resultHandler == null) {

        ensureNoOutParams(ms, boundSql);

        @SuppressWarnings("unchecked")

        List<E> list = (List<E>) tcm.getObject(cache, key);

        if (list == null) {

          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

          tcm.putObject(cache, key, list); // issue #578 and #116

        }

        return list;

      }

    }

    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

  }

 

 

 

6.    reflection

6.1 Invoker

 

 

6.1.1 MethodInvoker

 

org.apache.ibatis.reflection MethodInvoker主要内容

 

 

public class MethodInvoker implements Invoker {

 

  private final Class<?> type;

  private final Method method;

 

  public MethodInvoker(Method method) {

    this.method = method;

 

    if (method.getParameterTypes().length == 1) {

      type = method.getParameterTypes()[0];

    } else {

      type = method.getReturnType();

    }

  }

 

  @Override

  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {

    try {

      return method.invoke(target, args);

    } catch (IllegalAccessException e) {

      if (Reflector.canControlMemberAccessible()) {

        method.setAccessible(true);

        return method.invoke(target, args);

      } else {

        throw e;

      }

    }

  }

 

  @Override

  public Class<?> getType() {

    return type;

  }

}

 

 

 

6.1.2 GetFieldInvoker

 

org.apache.ibatis.reflection. GetFieldInvoker主要内容

 

public class GetFieldInvoker implements Invoker {

  private final Field field;

 

  public GetFieldInvoker(Field field) {

    this.field = field;

  }

 

  @Override

  public Object invoke(Object target, Object[] args) throws IllegalAccessException {

    try {

      return field.get(target);

    } catch (IllegalAccessException e) {

      if (Reflector.canControlMemberAccessible()) {

        field.setAccessible(true);

        return field.get(target);

      } else {

        throw e;

      }

    }

  }

 

  @Override

  public Class<?> getType() {

    return field.getType();

  }

}

 

 

 

6.1.3 SetFieldInvoker

 

org.apache.ibatis.reflection. GetFieldInvoker主要内容

 

public class SetFieldInvoker implements Invoker {

  private final Field field;

 

  public SetFieldInvoker(Field field) {

    this.field = field;

  }

 

  @Override

  public Object invoke(Object target, Object[] args) throws IllegalAccessException {

    try {

      field.set(target, args[0]);

    } catch (IllegalAccessException e) {

      if (Reflector.canControlMemberAccessible()) {

        field.setAccessible(true);

        field.set(target, args[0]);

      } else {

        throw e;

      }

    }

    return null;

  }

  @Override

  public Class<?> getType() {

    return field.getType();

  }

}

 

6.2 Reflector

 

org.apache.ibatis.reflection Reflector主要内容

 

 

public class Reflector {

 

  private final Class<?> type;

  private final String[] readablePropertyNames;

  private final String[] writablePropertyNames;

  private final Map<String, Invoker> setMethods = new HashMap<>();

  private final Map<String, Invoker> getMethods = new HashMap<>();

  private final Map<String, Class<?>> setTypes = new HashMap<>();

  private final Map<String, Class<?>> getTypes = new HashMap<>();

  private Constructor<?> defaultConstructor;

 

  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

 

  public Reflector(Class<?> clazz) {

    type = clazz;

    addDefaultConstructor(clazz);

    addGetMethods(clazz);

    addSetMethods(clazz);

    addFields(clazz);

    readablePropertyNames = getMethods.keySet().toArray(new String[0]);

    writablePropertyNames = setMethods.keySet().toArray(new String[0]);

    for (String propName : readablePropertyNames) {

      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);

    }

    for (String propName : writablePropertyNames) {

      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);

    }

  }

 

 

7.    binding

7.1 MapperProxy

 

org.apache.ibatis.binding. MapperProxy反射MapperMethod

 

 

public class MapperProxy<T> implements InvocationHandler, Serializable {

 

  private static final long serialVersionUID = -6424540398559729838L;

  private final SqlSession sqlSession;

  private final Class<T> mapperInterface;

  private final Map<Method, MapperMethod> methodCache;

 

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {

    this.sqlSession = sqlSession;

    this.mapperInterface = mapperInterface;

    this.methodCache = methodCache;

  }

 

  @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 (method.isDefault()) {

        return invokeDefaultMethod(proxy, method, args);

      }

    } catch (Throwable t) {

      throw ExceptionUtil.unwrapThrowable(t);

    }

    final MapperMethod mapperMethod = cachedMapperMethod(method);

    return mapperMethod.execute(sqlSession, args);

  }

 

  private MapperMethod cachedMapperMethod(Method method) {

    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));

  }

 

  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)

      throws Throwable {

    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class

        .getDeclaredConstructor(Class.class, int.class);

    if (!constructor.isAccessible()) {

      constructor.setAccessible(true);

    }

    final Class<?> declaringClass = method.getDeclaringClass();

    return constructor

        .newInstance(declaringClass,

            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED

                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)

        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);

  }

}

 

 

 

7.2 MapperMethod

 

org.apache.ibatis.binding. MapperMethod执行execute

 

 

public class MapperMethod {

 

  private final SqlCommand command;

  private final MethodSignature method;

 

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {

    this.command = new SqlCommand(config, mapperInterface, method);

    this.method = new MethodSignature(config, mapperInterface, method);

  }

 

  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);

          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;

  }

 

 

 

8.    mapping

8.1 BoundSql

 

org.apache.ibatis.mapping. BoundSql内容

 

public class BoundSql {

 

  private final String sql;

  private final List<ParameterMapping> parameterMappings;

  private final Object parameterObject;

  private final Map<String, Object> additionalParameters;

  private final MetaObject metaParameters;

}

 

 

8.2 MappedStatement

 

org.apache.ibatis.mapping. MappedStatement执行内容

 

public final class MappedStatement {

 

  private String resource;

  private Configuration configuration;

  private String id;

  private Integer fetchSize;

  private Integer timeout;

  private StatementType statementType;

  private ResultSetType resultSetType;

  private SqlSource sqlSource;

  private Cache cache;

  private ParameterMap parameterMap;

  private List<ResultMap> resultMaps;

  private boolean flushCacheRequired;

  private boolean useCache;

  private boolean resultOrdered;

  private SqlCommandType sqlCommandType;

  private KeyGenerator keyGenerator;

  private String[] keyProperties;

  private String[] keyColumns;

  private boolean hasNestedResultMaps;

  private String databaseId;

  private Log statementLog;

  private LanguageDriver lang;

  private String[] resultSets;

}

 

 

8.3 ParameterMapping

 

 

org.apache.ibatis.mapping. ParameterMapping内容

public class ParameterMapping {

 

  private Configuration configuration;

 

  private String property;

  private ParameterMode mode;

  private Class<?> javaType = Object.class;

  private JdbcType jdbcType;

  private Integer numericScale;

  private TypeHandler<?> typeHandler;

  private String resultMapId;

  private String jdbcTypeName;

  private String expression;

}

 

org.apache.ibatis.mapping. ParameterMap内容

 

 

public class ParameterMap {

  private String id;

  private Class<?> type;

  private List<ParameterMapping> parameterMappings;

 

 

8.4 ResultMapping

org.apache.ibatis.mapping. ResultMapping内容

 

 

public class ResultMapping {

  private Configuration configuration;

  private String property;

  private String column;

  private Class<?> javaType;

  private JdbcType jdbcType;

  private TypeHandler<?> typeHandler;

  private String nestedResultMapId;

  private String nestedQueryId;

  private Set<String> notNullColumns;

  private String columnPrefix;

  private List<ResultFlag> flags;

  private List<ResultMapping> composites;

  private String resultSet;

  private String foreignColumn;

  private boolean lazy;

}

 

 

 

 

org.apache.ibatis.mapping. ResultMap内容

 

 

  private Configuration configuration;

 

  private String id;

  private Class<?> type;

  private List<ResultMapping> resultMappings;

  private List<ResultMapping> idResultMappings;

  private List<ResultMapping> constructorResultMappings;

  private List<ResultMapping> propertyResultMappings;

  private Set<String> mappedColumns;

  private Set<String> mappedProperties;

  private Discriminator discriminator;

  private boolean hasNestedResultMaps;

  private boolean hasNestedQueries;

  private Boolean autoMapping;

 

}

 

 

 

 

9.    参考文献

 

Mybatis官网

https://blog.mybatis.org/p/about.html

 

Mybatis二级缓存

https://blog.csdn.net/qq_39470742/article/details/88600176

 

Mybatis基本原理

https://segmentfault.com/a/1190000041688841

 

Mybatis sqlsession流程

https://blog.csdn.net/javalingyu/article/details/124504454