mybatis0100- Mapper接口到SqlSession的跨越

    xiaoxiao2025-02-12  14

    文章目录

    1. mapper接口带来的便利2. sqlSeesion.getMapper(Class c)返回的对象是什么3. MapperProxy的Invoke方法4. mapperMethod.execute(sqlSession, args)方法

    1. mapper接口带来的便利

    如果是ibatis的时代,直接通过sqlSession对象调用方法,然后执行器等后续执行;

    SysRole sysRole = sqlSession.selectOne("com.honor.mybatis.mapper.SysRoleMapper.selectById", 1);

    mybatis的时候,我们可以不用操作sqlSession直接使用mapper接口。

    SysRoleMapper sysRoleMapper = sqlSession.getMapper(SysRoleMapper.class); SysRole sysRole = sysRoleMapper.selectById(1)

    2. sqlSeesion.getMapper(Class c)返回的对象是什么

    在MapperProxyFactory中发现这是通过jdk生成的代理对象

    protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }

    根据对jdk动态代理的理解,这个mapper的逻辑会落在代理执行程序上(newProxyInstance的第三个参数,实现了InvocationHandler),可以看到这个类是MapperProxy,最重要就是他得invoke方法

    3. MapperProxy的Invoke方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 判断的是调用的是mapper接口的方法还是Object的方法,method.getDeclaringClass()表示方法所属的类或接口。 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { // 判断是不是jdk1.8中有默认实现的方法 return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // 正常调用mapper接口中的方法,是会落在最后两句的 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }

    4. mapperMethod.execute(sqlSession, args)方法

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

    execute方法中,下面两句就是本次执行的落点

    Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param);

    其中第一句是将method的参数专称map对象,以便后续使用,具体规则如下

    public ParamNameResolver(Configuration config, Method method) { final Class<?>[] paramTypes = method.getParameterTypes(); final Annotation[][] paramAnnotations = method.getParameterAnnotations(); final SortedMap<Integer, String> map = new TreeMap<Integer, String>(); int paramCount = paramAnnotations.length; // get names from @Param annotations for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) { if (isSpecialParameter(paramTypes[paramIndex])) { // skip special parameters continue; } String name = null; for (Annotation annotation : paramAnnotations[paramIndex]) { if (annotation instanceof Param) { hasParamAnnotation = true; name = ((Param) annotation).value(); break; } } if (name == null) { // @Param was not specified. if (config.isUseActualParamName()) { name = getActualParamName(method, paramIndex); } if (name == null) { // use the parameter index as the name ("0", "1", ...) // gcode issue #71 name = String.valueOf(map.size()); } } map.put(paramIndex, name); } names = Collections.unmodifiableSortedMap(map); }

    最终的结果,如果配置了@Param优先使用,否则使用参数名作为map的key(useActualParamName可以配置,默认为true),如果useActualParamName配置为false,则使用“0”,“1”作为key。 然后就是执行sqlSession的selectOne方法了 至此就从mybatis进入了itbatis,mapper接口的的作用就完了

    最新回复(0)