Mybatis源码分析之--sql执行过程

时间:2022-05-13 16:55:02

上一篇文章讲解了sqlSession怎么获取,大致流程如下:

Mybatis源码分析之--sql执行过程

在获取的sqlSession后,我们会获取mapper,然后调用接口的方法,如下:

sqlSession= SqlSessionFactoryUtil.openSession();
studentMapper=sqlSession.getMapper(StudentMapper.class); int id=studentMapper.addStu(new Student("张六",12));
sqlSession.commit();

这样我们一条sql语句就执行完了,具体怎么运行的呢?

先看第一句getMapper的实现,首先找到sqlSession的实例类DefaultSqlSession:

    public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this); //sqlSession通过Configuration的getMapper来获取     }

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession); //Configuration通过mapperRegistry来获取     }

   public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if(mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);// 这里很重要,返回的是一个mapperProxy的实例             } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

public T newInstance(SqlSession sqlSession) {
        MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);     }


public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //这段代码是不是很熟悉? 用到了动态代理(之前写过一篇动态代理的蚊帐)。 throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);  //通过classLoader和interface接口数组获取代理类

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);//构造方法 final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h}); //返回一个新代理类的实例         } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

这样就生成了一个动态代理类,动态代理的为传入的class,在本例中为StudentMapper,返回的动态代理类实现了StudentMapper接口,继承了Proxy类,这样当StudentMapper的代理类实例调用接口addStu方法时,实际上是在执行动态代理中实现了invokeHandler接口的类的invoke方法,这里的这个类为MapperProxy类:

public class MapperProxy<T> implements InvocationHandler, Serializable {
 
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try {
            if(Object.class.equals(method.getDeclaringClass())) { //被代理的类对象, 方法的所在的类的类对象
                return method.invoke(this, args);
            }

            if(this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }

 MapperMethod mapperMethod = this.cachedMapperMethod(method);         return mapperMethod.execute(this.sqlSession, args); //返回给mapperMethod去执行     }
}
//具体执行,判断CRUD类型,然后根据类型选择sqlSession中的方法
public Object execute(SqlSession sqlSession, Object[] args) { Object param; Object result; switch(null.$SwitchMap$org$apache$ibatis$mapping$SqlCommandType[this.command.getType().ordinal()]) { case 1: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); break; case 2: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); break; case 3: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); break; case 4: if(this.method.returnsVoid() && this.method.hasResultHandler()) { this.executeWithResultHandler(sqlSession, args); result = null; } else if(this.method.returnsMany()) { result = this.executeForMany(sqlSession, args); } else if(this.method.returnsMap()) { result = this.executeForMap(sqlSession, args); } else if(this.method.returnsCursor()) { result = this.executeForCursor(sqlSession, args); } else { param = this.method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(this.command.getName(), param); } break; case 5: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + this.command.getName()); } if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { throw new BindingException("Mapper method \'" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); } else { return result; } }

Mybatis源码分析之--sql执行过程

 

根据本例,最终执行studentMapper.addStu是执行sqlSession.insert()方法,可以看到insert最终还是调用的update方法:

public int insert(String statement) {
        return this.insert(statement, (Object)null);
    }

    public int insert(String statement, Object parameter) {
        return this.update(statement, parameter);
    }

    public int update(String statement, Object parameter) {
        int var4;
        try {
            this.dirty = true;
            MappedStatement e = this.configuration.getMappedStatement(statement); //获取configuration下的执行语句
 var4 = this.executor.update(e, this.wrapCollection(parameter)); //最终的执行还是通过executor来执行         } catch (Exception var8) {
            throw ExceptionFactory.wrapException("Error updating database.  Cause: " + var8, var8);
        } finally {
            ErrorContext.instance().reset();
        }

        return var4;
    }
private Object wrapCollection(Object object) {//包装集合类
        DefaultSqlSession.StrictMap map;
        if(object instanceof Collection) {
            map = new DefaultSqlSession.StrictMap();
            map.put("collection", object);
            if(object instanceof List) {
                map.put("list", object);
            }

            return map;
        } else if(object != null && object.getClass().isArray()) {
            map = new DefaultSqlSession.StrictMap();
            map.put("array", object);
            return map;
        } else {
            return object;
        }
    }

update方法最终一层层调用会调用到SimpleExecutor中的doQuery方法:

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;

        int var6;
        try {
            Configuration configuration = ms.getConfiguration();
//newStatementHandler获取的为RoutingStatementHandler,同样是装饰器模式的实现,实现了StatementHandler接口并持有StatementHandler接口引用delegate。 StatementHandler handler
= configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null); stmt = this.prepareStatement(handler, ms.getStatementLog()); //预编译 var6 = handler.update(stmt); //最终执行 } finally { this.closeStatement(stmt); } return var6; }
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog); //获取连接,感兴趣可以追踪下去,其实也是用到了动态代理的方式来获取连接。
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
 
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        switch(null.$SwitchMap$org$apache$ibatis$mapping$StatementType[ms.getStatementType().ordinal()]) {
        case 1:
            this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 2:
            this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case 3:
            this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }

    }

 

我们来看一下StatementHandler的常用的实现类PreparedStatementHandler:

public class PreparedStatementHandler extends BaseStatementHandler { public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    }

    public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
 ps.execute(); //通过PreparedStatement来执行,是不是与在Java直接JDBC连接类似,获取conn,然后conn.prestatement(sql)执行 int rows = ps.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
        return rows;
    }
}

到目前为止,sql的执行过程讲解完成。

Mybatis源码分析之--sql执行过程