您的位置:首页 > 数据库

mybatis系列(四)--mybatis的核心:sql的执行流程(深入源码)

2016-10-14 11:51 1141 查看
先看mybaits是如何拿到sqlSession并执行sql的,当然sqlSession只是表面表面上执行sql,下面代码会讲到为什么。



                                                           (图片转载)

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
}
catch (IOException e) {}
}
}

public SqlSessionFactory build(Configuration config)
{
return new DefaultSqlSessionFactory(config);
}
}


拿到DefaultSqlSessionFactory之后,调用他的的openSession()方法

public SqlSession openSession() {
return openSessionFromDataSource(this.configuration.getDefaultExecutorType(), null, false);
}


然后调用openSessionFromDataSource()方法,创建DefaultSqlSession对象

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//通过configuration获取xml的配置信息之后,用Environment封装起来
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//这里的excutor很关键,其实是他去执行sql的,而不是sqlsession
Executor executor = this.configuration.newExecutor(tx, execType);
//然后创建DefaultSqlSession对象
return new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}



创建DefaultSqlSession对象之后,看到里面的方法名就知道,我们可以去执行sql了。



现在虽然拿到DefaultSqlSession了,但是还不知道怎么执行sql的。

在mybatis中是通过MapperProxy动态代理我们的Dao接口的。这也是mybatis的核心。先看拿到DefaultSqlSession后的执行流程



                                                              (图片转载)

public static void main(String[] args) {
SqlSession sqlSession=SqlSessionFactoryUtil.openSession();
//拿到sqlSession之后,执行getMapper方法
StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
Student student=new Student("我",11);
int result=studentMapper.add(student);
sqlSession.commit();
if(result>0){
System.out.println("添加成功!");
}
}

执行getMapper方法之后

//没有做什么,直接给了configuration去执行。
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}


//configuration还是什么都没做,直接给了mapperRegistry(mapper注册)去执行
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}

看看mapperRegistry的getMapper做了什么

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null)
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
//跟进去看看newInstance方法做了什么
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}


拿到MapperProxy之后,为每个dao创建动态代理

protected T newInstance(MapperProxy<T> mapperProxy)
{
//这个总算到了mybatis的核心了,这里创建了一个动态代理类
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[] { this.mapperInterface }, mapperProxy);
}

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


拿到MapperProxy之后,看下执行流程



(图片转载)

下面看是看看sql的具体执行过程,注意下面的return method.invoke(this, args);它永远不会执行,因为dao是接口

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);//这里的代码不会执行,而且永远不会执行,因为dao是接口
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//执行mapperMethod的execute方法
MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}

MapperMethod:可以看到这里判断要执行哪个方法

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (SqlCommandType.INSERT == this.command.getType()) {
Object param = this.method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(this.command.getName(), param)); } else { Object result;
if (SqlCommandType.UPDATE == this.command.getType()) {
Object param = this.method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(this.command.getName(), param)); } else { Object result;
if (SqlCommandType.DELETE == this.command.getType()) {
Object param = this.method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(this.command.getName(), param)); } else { Object result;
if (SqlCommandType.SELECT == this.command.getType()) { Object result;
if ((this.method.returnsVoid()) && (this.method.hasResultHandler())) {
executeWithResultHandler(sqlSession, args);
result = null; } else { Object result;
if (this.method.returnsMany()) {
result = executeForMany(sqlSession, args); } else { Object result;
if (this.method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
Object param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
}
} } else { throw new BindingException("Unknown execution method for: " + this.command.getName()); } } } }
Object result;
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() + ").");
}


执行sqlsession的selectList方法

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
//执行query方法
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}


最后调用doQuery方法

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
//StatementHandler封装了Statement, 让 StatementHandler 去处理
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}


最后看到JDBC的代码了,没错mybatis是对JDBC的分装
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//最后看到PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//结果交给了ResultSetHandler 去处理
return resultSetHandler.<E> handleResultSets(ps);
}

这样一条sql就执行完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: