串連MyBatis內部SqlSession與業務介面的代理類MapperProxy

來源:互聯網
上載者:User

標籤:

目的

系統中的業務介面需要調用MyBatis的SQL時,業務介面定義的參數不符合MyBatis自己內部的規範,那麼就需要把業務介面的參數轉換成MyBatis內部參數規,MapperProxy代理就完成了這一職責,下面就來分析一下。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    if (Object.class.equals(method.getDeclaringClass())) {      try {        return method.invoke(this, args);      } catch (Throwable t) {        throw ExceptionUtil.unwrapThrowable(t);      }    }    final MapperMethod mapperMethod = cachedMapperMethod(method);    return mapperMethod.execute(sqlSession, args);}private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;}

上面的invoke就是代理類回調的方法,而cachedMapperMethod方法,做了一個緩衝。這裡MapperMethod類的構造器與MapperMethod類的execute方法就是主要的邏輯,先來看一下MapperMethod構造器。

1 MapperMethod構造器

這裡有2個類的執行個體化,根據圖中的查詢分析一下這2個類。

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) throws BindingException {      // cn.vansky.schedule.time.menu.dao.MenuMapper.findMenuByUserId      String statementName = mapperInterface.getName() + "." + method.getName();      MappedStatement ms = null;      if (configuration.hasStatement(statementName)) {        ms = configuration.getMappedStatement(statementName);      } else if (!mapperInterface.equals(method.getDeclaringClass().getName())) { // issue #35        String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();        if (configuration.hasStatement(parentStatementName)) {          ms = configuration.getMappedStatement(parentStatementName);        }      }      if (ms == null) {        throw new BindingException("Invalid bound statement (not found): " + statementName);      }      // cn.vansky.schedule.time.menu.dao.MenuMapper.findMenuByUserId      name = ms.getId();      // SELECT      type = ms.getSqlCommandType();      if (type == SqlCommandType.UNKNOWN) {        throw new BindingException("Unknown execution method for: " + name);      }}public MethodSignature(Configuration configuration, Method method) throws BindingException {      // 傳回值類型Class      // interface java.util.List      this.returnType = method.getReturnType();      // 有無傳回值 true:無,false:有      // false      this.returnsVoid = void.class.equals(this.returnType);      // 傳回型別是否是集合Collection或者是數組      // true      this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());      // 傳回型別是Map,擷取註解MapKey      // 以上方法調用,值為null      this.mapKey = getMapKey(method);      // 傳回型別是否Map      // false      this.returnsMap = (this.mapKey != null);      // 參數是否有@Param註解      // true      this.hasNamedParameters = hasNamedParams(method);      // null      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);      // null      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);      // 擷取參數列表      // 0 -> userId       this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));}

SqlCommand類擷取處理的唯一標識及SQL語句類型,MethodSignature類對業務介面方法的入參類型及出參類型進行處理。

2 MapperMethed執行入口-->execute方法

public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    if (SqlCommandType.INSERT == command.getType()) {      // 新增      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.insert(command.getName(), param));    } else if (SqlCommandType.UPDATE == command.getType()) {      // 修改      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.update(command.getName(), param));    } else if (SqlCommandType.DELETE == command.getType()) {      // 刪除      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.delete(command.getName(), param));    } else if (SqlCommandType.SELECT == command.getType()) {      // 查詢      if (method.returnsVoid() && method.hasResultHandler()) {        // 無傳回值void        executeWithResultHandler(sqlSession, args);        result = null;      } else if (method.returnsMany()) {        // 集合Collection或數組        result = executeForMany(sqlSession, args);      } else if (method.returnsMap()) {        // Map        result = executeForMap(sqlSession, args);      } else {        // 唯一結果        Object param = method.convertArgsToSqlCommandParam(args);        result = sqlSession.selectOne(command.getName(), param);      }    } else {      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;}

增(INSERT)、改(UPDATE)、刪(DELETE),這3種操作可以歸納為一種,首先對業務介面的實際入參轉成MyBatis內部參數,然後調用SqlSession的處理方法,最後對結果進行處理,返回結果。

查(SELECT)有4中情況。

一:無傳回值

二:返回是集合Collection或者數組

三:返回是Map

四:返回一個結果

4種情況的具體細節不再分析。

總結

綜上首先需要先把業務介面的實際入參轉成MyBatis內部的參數,然後調用SqlSession相應的處理方法,最後對返回結果進行處理,在返回給業務介面。

串連MyBatis內部SqlSession與業務介面的代理類MapperProxy

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.