MyBatis核心源码深度剖析SQL语句执行过程

目录
  • 1 SQL语句的执行过程介绍
  • 2 SQL执行的入口分析
    • 2.1 为Mapper接口创建代理对象
    • 2.2 执行代理逻辑
  • 3 查询语句的执行过程分析
    • 3.1 selectOne方法分析
    • 3.2 sql获取
    • 3.3 参数设置
    • 3.4 SQL执行和结果集的封装
  • 4 更新语句的执行过程分析
    • 4.1 sqlsession增删改方法分析
    • 4.2 sql获取
    • 4.3 参数设置
    • 4.4 SQL执行
  • 5 小结

1 SQL语句的执行过程介绍

MyBatis核心执行组件:

2 SQL执行的入口分析

2.1 为Mapper接口创建代理对象

// 方式1:
User user = session.selectOne("com.oldlu.dao.UserMapper.findUserById", 101);
// 方式2:
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.findAll();

2.2 执行代理逻辑

方式1入口分析:
session是DefaultSqlSession类型的,因为sqlSessionFactory默认生成的SqlSession是
DefaultSqlSession类型。
selectOne()会调用selectList()。

// DefaultSqlSession类
public <E> List<E> selectList(String statement, Object parameter, RowBounds
rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    // CURD操作是交给Excetor去处理的
    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入口分析:
获取代理对象:

//DefaultSqlSession类 ====================>
@Override
public <T> T getMapper(Class<T> type) {
  return configuration.getMapper(type, this);
  }
// Configuration类 ====================>
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}
//MapperRegistry ----> apperProxyFactory.newInstance ====================>
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  //从缓存中获取该Mapper接口的代理工厂对象
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>)
knownMappers.get(type);
  //如果该Mapper接口没有注册过,则抛异常
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the
MapperRegistry.");
 }
  try {
    //【使用代理工厂创建Mapper接口的代理对象】
    return mapperProxyFactory.newInstance(sqlSession);
 } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e,
e);
 }
}
//MapperProxyFactory  --->此时生成代理对象 ====================>
protected T newInstance(MapperProxy<T> mapperProxy) {
  //Mybatis底层是调用JDK的Proxy类来创建代理实例
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new
Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession,
mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

代理对象执行逻辑:

//MapperProxy   ====================>
/**代理对象执行的方法,代理以后,所有Mapper的方法调用时,都会调用这个invoke方法*/
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
 try {
  if (Object.class.equals(method.getDeclaringClass())) {
   //如果是Object方法,则调用方法本身
   return method.invoke(this, args);
 } else {
   //调用接口方法:根据被调用接口的Method对象,从缓存中获取MapperMethodInvoker对象
   //apper接口中的每一个方法都对应一个MapperMethodInvoker对象,而MapperMethodInvoker
对象里面的MapperMethod保存着对应的SQL信息和返回类型以完成SQL调用 ...
   return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
 }
} catch (Throwable t) {
  throw ExceptionUtil.unwrapThrowable(t);
}
}
/**
获取缓存中MapperMethodInvoker,如果没有则创建一个,而MapperMethodInvoker内部封装这一
个MethodHandler
*/
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  try {
    return methodCache.computeIfAbsent(method, m -> {
      if (m.isDefault()) {
        //如果调用接口的是默认方法(default方法)
        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 {
        //如果调用的普通方法(非default方法),则创建一个PlainMethodInvoker并放
入缓存,其中MapperMethod保存对应接口方法的SQL以及入参和出参的数据类型等信息
        return new PlainMethodInvoker(new MapperMethod(mapperInterface,
method, sqlSession.getConfiguration()));
     }
   });
 } catch (RuntimeException re) {
    Throwable cause = re.getCause();
throw cause == null ? re : cause;
 }
}
// MapperProxy内部类: PainMethodInvoker  ====================>
// 当cacheInvoker返回了PalinMethodInvoker实例之后,紧接着调用了这个实例的
PlainMethodInvoker:invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession
sqlSession) throws Throwable {
 //Mybatis实现接口方法的核心: MapperMethod::execute方法:
 return mapperMethod.execute(sqlSession, args);
}
// MapperMethod  ====================>
public Object execute(SqlSession sqlSession, Object[] args) {
  Object result;
  switch (command.getType()) {
    case INSERT: {
      // 将args进行解析,如果是多个参数则,则根据@Param注解指定名称将参数转换为Map,
如果是封装实体则不转换
      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 {
        //解析参数,因为SqlSession::selectOne方法参数只能传入一个,但是我们
Mapper中可能传入多个参数,
        //有可能是通过@Param注解指定参数名,所以这里需要将Mapper接口方法中的多个参
数转化为一个ParamMap,
        //也就是说如果是传入的单个封装实体,那么直接返回出来;如果传入的是多个参数,
实际上都转换成了Map
        Object param = method.convertArgsToSqlCommandParam(args);
        //可以看到动态代理最后还是使用SqlSession操作数据库的
        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;
}
// 此时我们发现: 回到了sqlsession中
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
  List<E> result;
  Object param = method.convertArgsToSqlCommandParam(args);
  if (method.hasRowBounds()) {
   RowBounds rowBounds = method.extractRowBounds(args);
   result = sqlSession.selectList(command.getName(), param, rowBounds);
 } else {
   result = sqlSession.selectList(command.getName(), param);
 }
 // ...
  return result;
}

3 查询语句的执行过程分析

3.1 selectOne方法分析

// DefaultSqlSession类  ===============>
// selectOne
@Override
public <T> T selectOne(String statement, Object parameter) {
  // //selectOne()会调用selectList()。
  List<T> list = this.selectList(statement, parameter);
  if (list.size() == 1) {
    return list.get(0);
 } else if (list.size() > 1) {
    throw new TooManyResultsException("Expected one result (or null) to be
returned by selectOne(), but found: " + list.size());
 } else {
    return null;
 }
}
// selectList
public <E> List<E> selectList(String statement, Object parameter, RowBounds
rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    // CURD操作是交给Excetor去处理的
    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();
 }
}

3.2 sql获取

// CachingExecutor ===============>
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds
rowBounds, ResultHandler resultHandler) throws SQLException {
  // 获取绑定的sql命令,比如"SELECT * FROM xxx"
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@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);
}
//真正执行query操作的是SimplyExecutor代理来完成的,SimplyExecutor的父类BaseExecutor的
query方法中:
// BaseExecutor类:SimplyExecutor的父类 =================>
@Override
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++;
    //localCache是一级缓存,如果找不到就调用queryFromDatabase从数据库中查找
    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();
   }
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      clearLocalCache();
   }
}
  return list;
}
//第一次,没有缓存,所以会调用queryFromDatabase方法来执行查询。
private <E> List<E> queryFromDatabase(...) 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;
}
// SimpleExecutor类 ============================>
public <E> List<E> doQuery(...) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(....);
    // 1:SQL查询参数的设置
    stmt = prepareStatement(handler, ms.getStatementLog());
    // StatementHandler封装了Statement
    // 2:SQL查询操作和结果集的封装
    return handler.<E>query(stmt);
 } finally {
    closeStatement(stmt);
 }
}

3.3 参数设置

// SimplyExecutor类 ============================>
// 【1】 参数设置: prepareStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog)
throws SQLException {
  Statement stmt;
  // 通过getConnection方法来获取一个Connection,
  Connection connection = getConnection(statementLog);
  // 调用prepare方法来获取一个Statement
  stmt = handler.prepare(connection, transaction.getTimeout());

  // 设置SQL查询中的参数值 ***
  handler.parameterize(stmt);
  return stmt;
}
// RoutingStatementHandler ============================>
// PreparedStatementHandler ============================>
@Override
public void parameterize(Statement statement) throws SQLException {
  parameterHandler.setParameters((PreparedStatement) statement);
}
// DefaultParameterHandler ============================> 此时参数设置成功
@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)) {
          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.....");
       }
     }
   }
 }
}

3.4 SQL执行和结果集的封装

// RoutingStatementHandler ============================>
@Override
public <E> List<E> query(Statement statement) throws SQLException {
  return delegate.<E>query(statement);
}
// PreparedStatementHandler ============================>
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException {
  // 这里就到了熟悉的PreparedStatement了
  PreparedStatement ps = (PreparedStatement) statement;
  // 执行SQL查询操作
  ps.execute();
  // 结果交给ResultHandler来处理
  return resultSetHandler.<E> handleResultSets(ps);
}
// DefaultResultSetHandler类(封装返回值,将查询结果封装成Object对象)
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
  ErrorContext.instance().activity("handling
results").object(mappedStatement.getId());
  final List<Object> multipleResults = new ArrayList<Object>();
  int resultSetCount = 0;
  ResultSetWrapper rsw = getFirstResultSet(stmt);
  List<ResultMap> resultMaps = mappedStatement.getResultMaps();
 int resultMapCount = resultMaps.size();
  validateResultMapsCount(rsw, resultMapCount);
  while (rsw != null && resultMapCount > resultSetCount) {
    ResultMap resultMap = resultMaps.get(resultSetCount);
    handleResultSet(rsw, resultMap, multipleResults, null);
    rsw = getNextResultSet(stmt);
    cleanUpAfterHandlingResultSet();
    resultSetCount++;
 }
  String[] resultSets = mappedStatement.getResultSets();
  if (resultSets != null) {
    while (rsw != null && resultSetCount < resultSets.length) {
      ResultMapping parentMapping =
nextResultMaps.get(resultSets[resultSetCount]);
      if (parentMapping != null) {
        String nestedResultMapId = parentMapping.getNestedResultMapId();
        ResultMap resultMap =
configuration.getResultMap(nestedResultMapId);
        handleResultSet(rsw, resultMap, null, parentMapping);
     }
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
   }
 }
  return collapseSingleResultList(multipleResults);
}

4 更新语句的执行过程分析

  • xecutor 的 update 方法分析
  • insert、update 和 delete 操作都会清空一二级缓存
  • doUpdate 方法
  • PreparedStatementHandler 的 update 方法
  • 默认是创建PreparedStatementHandler,然后执行prepareStatement方法。
  • 执行结果为受影响行数
  • 执行更新语句的SQL

4.1 sqlsession增删改方法分析

// DefaultSqlSession ===============>
@Override
 public int insert(...) {
  return update(statement, parameter);
}
 @Override
 public int update(String statement) {
  return update(statement, null);
}
 @Override
  public int delete(...) {
  return update(....);
}
// insert 、delete操作是通过调用update语句进行的相关逻辑
 @Override
 public int update(String statement, Object parameter) {
  try {
   dirty = true;
   MappedStatement ms = configuration.getMappedStatement(statement);
   // 增删改 最终底层都是 update
   return executor.update(ms, wrapCollection(parameter));

 } catch (Exception e) {
   throw ExceptionFactory.wrapException("Error updating database. Cause: " +
e, e);
 } finally {
   ErrorContext.instance().reset();
 }
}

4.2 sql获取

// CachingExecutor  ===============>
@Override
public int update(MappedStatement ms, Object parameterObject) throws
SQLException {
  // 执行增删改,清除缓存
  flushCacheIfRequired(ms);
  // 跳转BaseExecutor
  return delegate.update(ms, parameterObject);
}
// BaseExecutor   ===============>
@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.");
 }
  // 清除 LocalCache 一级缓存
  clearLocalCache();
  //执行 doUpdate
  return doUpdate(ms, parameter);
}
// SimpleExecutor  ===============>
// doUpdate
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(...);
    // 【1】.获取statement,并进行参数映射
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 【2】.handler.update()方法执行具体sql指令
    return handler.update(stmt);
 } finally {
    closeStatement(stmt);
 }
}

4.3 参数设置

// SimplyExecutor类 ============================>
//【1】 prepareStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog)
throws SQLException {
  Statement stmt;
  Connection connection = getConnection(statementLog);
  // 使用connection对象信息创建statement,并将超时时间绑定
  stmt = handler.prepare(connection, transaction.getTimeout());
  // parameterize方法设置sql执行时候需要的参数
  handler.parameterize(stmt);
  return stmt;
}
// RoutingStatementHandler ============================>
// PreparedStatementHandler ============================>
@Override
public void parameterize(Statement statement) throws SQLException {
  parameterHandler.setParameters((PreparedStatement) statement);
}
// DefaultParameterHandler ============================> 此时参数设置成功
@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)) {
          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.....");
       }
     }
   }
 }
}

4.4 SQL执行

// RoutingStatementHandler ============================>
 @Override
 public int update(Statement statement) throws SQLException {
  return delegate.update(statement);
}
// PreparedStatementHandler ============================>
@Override
public int update(Statement statement) throws SQLException {
  // 这里就是底层JDBC的PreparedStatement 操作了
  PreparedStatement ps = (PreparedStatement) statement;
  // 执行SQL增删改操作
  ps.execute();
  // 获取影响的行数
  int rows = ps.getUpdateCount();
  Object parameterObject = boundSql.getParameterObject();
  KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
  keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
  // 返回影响的行数
  return rows;
}

5 小结

mybatis执行SQL的流程都是:
1.根据statement字符串从configuration中获取对应的mappedStatement;
2.根据获取的mappedStatement创建相应的Statement实例;
3.根据传入的参数对statement实例进行参数设置;
4.执行statement并执行后置操作;

到此这篇关于MyBatis核心源码深度剖析SQL执行过程的文章就介绍到这了,更多相关MyBatis核心源码剖析SQL执行过程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一条 SQL 语句执行过程

    目录 一.MySQL体系架构 -连接池组件 -缓存组件 -分析器 -优化器 -执行器 二.写操作执行过程 三.读操作执行过程 四.SQL执行顺序 一.MySQL 体系架构 - 连接池组件 1.负责与客户端的通信,是半双工模式,这就意味着某一固定时刻只能由客户端向服务器请求或者服务器向客户端发送数据,而不能同时进行. 2.验证用户名和密码是否正确(数据库 MySQL 的 user 表中进行验证),如果错误返回错误通知Access denied for user 'root'@'localhost'

  • mybatis源码解读之executor包懒加载功能 

    ProxyFactory是创建代理类的工厂接口,其中的setProperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置.createProxy方法用来创建一个代理对象 public interface ProxyFactory {   // 设置工厂属性   default void setProperties(Properties properties) {   }   // 创建代理对象   Object createProxy(O

  • mybatis源码解读之executor包语句处理功能

    1.mybatis对多语句类型的支持 在mybatis映射文件中传参数,主要用到#{} 或者 ${}. #{}:表示使用这种符号的变量会以预编译的形式赋值到sql片段中. ${}:表示使用这种符号的变量会以字符串的形式直接插到sql片段中. mybatis中支持三种语句类型,不同语句类型支持的变量符号不同.mybatis的三种类型如下: STATEMENT:这种语句类型中,只会对sql片段进行简单的字符串拼接.只支持使用${}. PREPARED:这种语句中会先对sql片段进行字符串拼接,然后再

  • mybatis源码解读-Java中executor包的语句处理功能

    目录 1.mybatis对多语句类型的支持 2.mybatis的语句处理功能 1.mybatis对多语句类型的支持 在mybatis映射文件中传参数,主要用到#{} 或者 ${}. #{}:表示使用这种符号的变量会以预编译的形式赋值到sql片段中. ${}:表示使用这种符号的变量会以字符串的形式直接插到sql片段中. mybatis中支持三种语句类型,不同语句类型支持的变量符号不同.mybatis的三种类型如下: STATEMENT:这种语句类型中,只会对sql片段进行简单的字符串拼接.只支持使

  • MyBatis核心源码深度剖析SQL语句执行过程

    目录 1 SQL语句的执行过程介绍 2 SQL执行的入口分析 2.1 为Mapper接口创建代理对象 2.2 执行代理逻辑 3 查询语句的执行过程分析 3.1 selectOne方法分析 3.2 sql获取 3.3 参数设置 3.4 SQL执行和结果集的封装 4 更新语句的执行过程分析 4.1 sqlsession增删改方法分析 4.2 sql获取 4.3 参数设置 4.4 SQL执行 5 小结 1 SQL语句的执行过程介绍 MyBatis核心执行组件: 2 SQL执行的入口分析 2.1 为Ma

  • MySql中sql语句执行过程详细讲解

    目录 前言: sql语句的执行过程: 查询缓存: 分析器: 优化器: 执行器: 总结 前言: 很多人都在使用mysql数据库,但是很少有人能够说出来整个sql语句的执行过程是怎样的,如果不了解执行过程的话,就很难进行sql语句的优化处理,也很难设计出来优良的数据库表结构.这篇文章主要是讲解一下sql语句的执行过程. sql语句的执行过程: 客户端.连接器.分析器.优化器.执行器.存储引擎几个阶段. 连接器的作用:管理链接.权限验证的处理. 分析器的作用:词法分析.语法分析. 优化器的作用:执行计

  • Java MyBatis是如何执行一条SQL语句的

    目录 背景 阅读环境 阅读过程 加载XML的过程 创建Mapper 获得一个Mapper 执行一个Mapper的方法 结论 背景 在前两天的一次面试中,面试官问了一个和标题一样的问题,由于一直认为MyBatis只是一个ORM框架,所以并没有对他有过深入的了解,于是被问到了,那么这一篇文章来从源码探究一下MyBatis是如何执行一条SQL语句的. 阅读环境 源码环境,github直接下载的main分支代码,版本号为 3.5.11-SNAPSHOT Ide Jetbrain Idea 2021.2.

  • 根据mysql慢日志监控SQL语句执行效率

    根据mysql慢日志监控SQL语句执行效率 启用MySQL的log-slow-queries(慢查询记录). 在Linux环境下先要找到my.cnf文件(一般在/etc/mysql/),然后可能会发现该文件修改后无法保存,原因是你没有相应的权限,可以从属性中看到该文件的所有者是root,这时要先以root的身份打开它: sudo nautilus /etc/mysql 接着再打开my.cnf文件然后找到[mysqld]标签在下面加上: log-slow-queries=/path/slow.lo

  • SQL语句执行顺序详解

    我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,由于SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管SELECT语句第一个出现,但是几乎总是最后被处理. 每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入.这些虚拟表对调用者(客户端应用程序或者外部查询)不可用.只是最后一步生成的表才会返回 给调用者.如果没有在查询中指定某一子句,将跳过

  • 腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列(推荐)

    说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你"输入URL回车之后,究竟发生了什么"一样,看看你能说出多少了. 之前腾讯面试的实话,也问到这个问题了,不过答的很不好,之前没去想过相关原因,导致一时之间扯不出来.所以今天,我带大家来详细扯一下有哪些原因,相信你看完之后一定会有所收获,不然你打我. 开始装逼:分类讨论 一条 SQL 语句执行的很慢,那是每次执行都很慢呢?还是大多数情况下是正常的,偶尔出现很慢呢?所以我觉得,我们还得

  • SQL语句执行超时引发网站首页访问故障问题

    非常抱歉,今天早上 6:37~8:15 期间,由于获取网站首页博文列表的 SQL 语句出现突发的查询超时问题,造成访问网站首页时出现 500 错误,由此给您带来麻烦,请您谅解. 故障的情况是这样的. 故障期间日志中记录了大量下面的错误. 2020-02-03 06:37:24.635 [Error] An unhandled exception has occurred while executing the request./Microsoft.AspNetCore.Diagnostics.E

  • 了解MySQL查询语句执行过程(5大组件)

    目录 开篇 查询请求的执行流程 MySQL组件定义 连接器 查询缓存 分析器 优化器 逻辑变换 代价优化 执行器 总结 开篇 相信广大程序员朋友经常使用MySQL数据库作为书籍持久化的工具,我们最常使用的就是MySQL中的SQL语句,从客户端向MySQL发出一条条指令,然后获取返回的数据结果进行后面的逻辑处理.尽管大家经常使用SQL语句完成工作,你是否关注过其执行的阶段,利用了哪些技术完成?今天,就带大家一起看看MySQL数据库处理SQL请求的全过程.下面将会讲述如下内容: 查询请求在MySQL

  • MyBatis MapperProvider MessageFormat拼接批量SQL语句执行报错的原因分析及解决办法

    最近在项目中有这么一段代码:下载服务器基础业务数据进行本地批量插入操作,因项目中使用mybatis进行持久化操作,故直接考虑使用mybatis的批量插入功能. 1.以下是Mapper接口的部分代码 public interface PrintMapper { @InsertProvider(type = PrintMapperProvider.class,method = "insertAllLotWithVehicleCode4H2") void insertAllLotWithVe

随机推荐