mybatis执行流程

一、第一阶段 getMapper

1.通过sqlSession.getMapper(Class)

在这里插入图片描述

MemberDao mapper = sqlSession.getMapper(MemberDao.class);
2.DefaultSqlSession

在这里插入图片描述

调用sqlSession的实现DefaultSqlSession中的getMapper方法

  @Override
  public <T> T getMapper(Class<T> type) {//type dao.class
    return configuration.<T>getMapper(type, this);
  }
3.Configuration

在这里插入图片描述

通过configuration中的getMapper方法,将type和DefaultSqlSession传递过去

private final Configuration configuration;

return configuration.<T>getMapper(type, this);
//this ---> DefaultSqlSession

通过MapperRegistry 去调用里面的getMapper(Class type, SqlSession sqlSession)方法

protected final MapperRegistry mapperRegistry = new MapperRegistry(this);


public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
4.MapperRegistry

在这里插入图片描述

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
      // 根据指定的type,查找对应的MapperProxyFactory对象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
      //如果没有配置mapper,则找不到对应的MapperProxyFactory , 抛出异常
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
        //mapperProxyFactory.newInstance(sqlSession); 生成相应的代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
5.MapperProxyFactory

创建MapperProxy对象 ,每次调用都对重新创建,使用动态代理,将mapperProxy返回出去

在这里插入图片描述

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

流程

SqlSession (getMapper) —> SqlSessionTemplate implements SqlSessio (getMapper) —> Configuration (getMapper) —> MapperRegistry (getMapper) ----> MapperProxyFactory (newInstance) —>(return) || Configuration ----> SqlSessionTemplate —> SqlSession

二、第二阶段 getMapper.xxx

1.MapperProxy

在这里插入图片描述

  @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 (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
     //缓存mapperMapperMethod实例
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
1.1 cachedMapperMethod
  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
      //判断method 是否在缓存中,不存在的话就去创建一个mapperMethod
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }
1.2 MapperMethod

在这里插入图片描述

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {    this.command = new SqlCommand(config, mapperInterface, method);//负责获取dao中的名字id,使用的数据库,以及数据的操作方式,SELECR、INSERT。。。    this.method = new MethodSignature(config, mapperInterface, method);//负责判断返回值的类型  }
1 SqlCommand
  • 负责获取dao中的名字id,使用的数据库,以及数据的操作方式,SELECR、INSERT。。。
public static class SqlCommand {    private final String name; //dao的名字/方法名    private final SqlCommandType type; //操作的类型 例如UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {      final String methodName = method.getName(); // 获取要进行操作的方法名        //获取方法声明的接口类型      final Class<?> declaringClass = method.getDeclaringClass();        //获取xml中每个方法构建的MappedStatement        MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,          configuration);      if (ms == null) {        if (method.getAnnotation(Flush.class) != null) {          name = null;          type = SqlCommandType.FLUSH;        } else {          throw new BindingException("Invalid bound statement (not found): "              + mapperInterface.getName() + "." + methodName);        }      } else {        name = ms.getId();//获取xml中的 id        type = ms.getSqlCommandType();//获取操作的类型UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;        if (type == SqlCommandType.UNKNOWN) {          throw new BindingException("Unknown execution method for: " + name);        }      }    }
2 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();      }    //判断返回值是否为空      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);    //获取到mapKey 即@MapKey值      this.mapKey = getMapKey(method);    //是否返回map      this.returnsMap = this.mapKey != null;    //参数中是否有RowBounds  即mybatis的分页工具类      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);    //是否有ResultHandler类      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);    //获取到参数值  即@Param的值,如果有则为里面的value值  如果没有 则为'0','1','2'之类的      this.paramNameResolver = new ParamNameResolver(configuration, method);    }
1.3 mapperMethod.execute()

在这里插入图片描述

public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    switch (command.getType()) { //执行判断方法command.getType()为要操作的操作类型UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH      case INSERT: {      Object param = method.convertArgsToSqlCommandParam(args); //参数转换        result = rowCountResult(sqlSession.insert(command.getName(), param)); //sql执行        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);            //返回map        } else if (method.returnsMap()) {          result = executeForMap(sqlSession, args);            //返回Cursor        } else if (method.returnsCursor()) {            //返回单个对象          result = executeForCursor(sqlSession, args);        } else {          Object param = method.convertArgsToSqlCommandParam(args);          result = sqlSession.selectOne(command.getName(), param);        }        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执行完成返回结果集  }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值