mybatis系列(四)--mybatis的核心:sql的执行流程(深入源码)
2016-10-14 11:51
1141 查看
先看mybaits是如何拿到sqlSession并执行sql的,当然sqlSession只是表面表面上执行sql,下面代码会讲到为什么。
(图片转载)
拿到DefaultSqlSessionFactory之后,调用他的的openSession()方法
然后调用openSessionFromDataSource()方法,创建DefaultSqlSession对象
创建DefaultSqlSession对象之后,看到里面的方法名就知道,我们可以去执行sql了。
现在虽然拿到DefaultSqlSession了,但是还不知道怎么执行sql的。
在mybatis中是通过MapperProxy动态代理我们的Dao接口的。这也是mybatis的核心。先看拿到DefaultSqlSession后的执行流程
(图片转载)
执行getMapper方法之后
看看mapperRegistry的getMapper做了什么
拿到MapperProxy之后,为每个dao创建动态代理
拿到MapperProxy之后,看下执行流程
(图片转载)
下面看是看看sql的具体执行过程,注意下面的return method.invoke(this, args);它永远不会执行,因为dao是接口
MapperMethod:可以看到这里判断要执行哪个方法
执行sqlsession的selectList方法
最后调用doQuery方法
最后看到JDBC的代码了,没错mybatis是对JDBC的分装
这样一条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就执行完了。
相关文章推荐
- Glide系列第二弹,从源码的角度深入理解Glide的执行流程
- MyBatis源码学习系列:02-核心接口SqlSessionFactory和SqlSession
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)(转)
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- 转 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- MyBatis 源码解析:通过源码深入理解 SQL 的执行过程
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- Mybatis源码(三)之SqlSession执行流程全貌
- Mybatis 源码 sql执行流程分析
- MyBatis源码分析-SQL语句执行的完整流程
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)
- MyBatis 源码解析:通过源码深入理解 SQL 的执行过程
- Glide系列之二:从源码的角度深入理解Glide的执行流程
- mybatis源码分析,sql语句执行的完整流程
- MyBatis源码学习笔记(十)SQL执行流程分析
- 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)