上一篇文章讲解了sqlSession怎么获取,大致流程如下:
在获取的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; } }
根据本例,最终执行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的执行过程讲解完成。