深度分析:mybatis的底层实现原理,看完你学会了吗?( 二 )


从核心配置文件mybatis-config.xml中获取Environment(这里面是数据源); 从Environment中取得DataSource; 从Environment中取得TransactionFactory; 从DataSource里获取数据库连接对象Connection; 在取得的数据库连接上创建事务对象Transaction; 创建Executor对象(该对象非常重要,事实上sqlsession的所有操作都是通过它完成的); 创建sqlsession对象 。
我们对Executor对象着重讲下,因为该对象是执行sql的实现类: 进入 Executor executor = this.configuration.newExecutor(tx, execType)方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}可以看出,如果开启cache的话,会创建CachingExecutor,否则创建普通Executor,普通Executor有3个基础类型,BatchExecutor专门用于执行批量sql操作,ReuseExecutor会重用statement执行sql操作,SimpleExecutor只是简单执行sql没有什么特别的 。而CachingExecutor在查询数据库前先查找缓存,若没找到的话调用delegate(就是构造时传入的Executor对象)从数据库查询,并将查询结果存入缓存中 。Executor对象是可以被插件拦截的,如果定义了针对Executor类型的插件,最终生成的Executor对象是被各个插件插入后的代理对象 。我们简单的看下其3个基本基础类型中最简单的SimpleExecutor 是怎么执行sql的
public class SimpleExecutor extends BaseExecutor {public SimpleExecutor(Configuration configuration, Transaction transaction) {super(configuration, transaction);}public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null;int var6;try {//拿到Configuration 属性Configuration configuration = ms.getConfiguration();//拿到StatementHandlerStatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);//拿到prepareStatementstmt = this.prepareStatement(handler, ms.getStatementLog());//prepareStatement执行sqlvar6 = handler.update(stmt);} finally {this.closeStatement(stmt);}return var6;}StatementHandler可以看出,Executor本质上也是个甩手掌柜,具体的事情原来是StatementHandler来完成的 。当Executor将指挥棒交给StatementHandler后,接下来的工作就是StatementHandler的事了 。我们先看看StatementHandler是如何创建的 。
publicStatementHandler newStatementHandler(Executor executor, MappedStatementmappedStatement,ObjectparameterObject, RowBounds rowBounds, ResultHandler resultHandler) {StatementHandler statementHandler = newRoutingStatementHandler(executor, mappedStatement,parameterObject,rowBounds, resultHandler);statementHandler= (StatementHandler) interceptorChain.pluginAll(statementHandler);returnstatementHandler;}可以看到每次创建的StatementHandler都是RoutingStatementHandler,它只是一个分发者,他一个属性delegate用于指定用哪种具体的StatementHandler 。可选的StatementHandler有SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler三种 。选用哪种在mapper配置文件的每个statement里指定,默认的是PreparedStatementHandler 。同时还要注意到StatementHandler是可以被拦截器拦截的,和Executor一样,被拦截器拦截后的对象是一个代理对象 。例如像实现数据库的物理分页,众多物理分页的实现都是在这个地方使用拦截器实现的
看完了Executor具体执行过程,还没结束,我们还不知道在执行前一步,就是代码块前两步,到底做了什么关联,再一次贴出来:
.....//通过sqlSessionFactory获取sqlSessionSqlSession sqlSession = sqlSessionFactory.openSession();1、TbUserMapper userMapper = sqlSession.getMapper(TbUserMapper.class);2、TbUser user = new TbUser("liybk", "liybk","186..","123");3、userMapper.insertUser(user);那么这个mapper作用到底是什么呢,它是如何创建的呢,它又是怎么与sqlsession等关联起来的呢? 我们进入方法:
public <T> T getMapper(Class<T> type) {return this.configuration.getMapper(type, this);}最终调用的是configuration的mapperRegistry方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return this.mapperRegistry.getMapper(type, sqlSession);}//mapperRegistrypublic <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.");} else {try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception var5) {throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);}}}//mapperProxyFactory public T newInstance(SqlSession sqlSession) {MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);return this.newInstance(mapperProxy);}protected T newInstance(MapperProxy<T> mapperProxy) {return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);}


推荐阅读