博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
连接MyBatis内部SqlSession与业务接口的代理类MapperProxy
阅读量:7052 次
发布时间:2019-06-28

本文共 5292 字,大约阅读时间需要 17 分钟。

hot3.png

目的

系统中的业务接口需要调用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构造器。

MapperMethod构造器

093338_rsDi_1269959.png

这里有2个类的实例化,根据图中的查询分析一下这2个类。

101519_sinv_1269959.png

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类对业务接口方法的入参类型及出参类型进行处理。

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相应的处理方法,最后对返回结果进行处理,在返回给业务接口。

转载于:https://my.oschina.net/u/1269959/blog/524486

你可能感兴趣的文章
Ubuntu机器学习python实战(一)k-近邻算法
查看>>
Reachability(判断网络是否连接)
查看>>
sql奇特的语句
查看>>
安卓之文件结构
查看>>
java 线程
查看>>
嵌入式,代码调试----GDB扫盲
查看>>
IDEA 关于maven项目引入css ,js,image文件 路径的问题
查看>>
进度一
查看>>
composer 安装Laravel
查看>>
项目2.0上线,回想过后杂谈总结基础回顾一番
查看>>
冲刺一 (day 3)
查看>>
Beep使用
查看>>
关于php网络爬虫phpspider。
查看>>
OpenGL的glRotatef旋转变换函数详解
查看>>
c#中 ==与equals有什么区别
查看>>
Oracle Group By ROLLUP-SubTotal
查看>>
PHP 正则表达式
查看>>
Computer Graphics Research Software
查看>>
nodejs进阶(2)—函数模块调用
查看>>
java面向对象高级分层实例_BaseDao
查看>>