Mybatis工作流程
Mybatis初始化流程
1.获取配置文件(即获取一个InputStream)2.创建SqlSessionFactoryBuilder对象3.创建SqlSessionFactory对象(细分为3步)
3.创建SqlSessionFactory对象的过程3.1构造XMLConfigBuilder对象(用于解析配置文件)3.2解析配置文件(细分为多步)3.3实例化SqlSessionFactory对象
3.2解析配置文件简单叙述一下,即把xml里面的配置信息进行解析,并存储到Configuration的容器中。 |
总结
1.SqlSessionFactory是Mybatis的核心类,可以提供SqlSession,以SqlSession的形式执行SQL。
2.Configuration用于存储xml的配置信息如SQL等。
什么是SqlSession?
其实SqlSession只是一个门面,实际是由Executor来执行SQL的
SqlSession与Mapper接口的关系是什么?(两种SQL执行的门面,现在多用Mapper)
SqlSession提供了一个getMapper方法,可以获取Mapper接口,看源码可知Mapper的Bean最终由动态代理实现。https://www.cnblogs.com/dongying/p/4142476.html
而Mapper的执行其实是通过Executor、StatementHandler、ParameterHandler和ResultHandler来完成数据操作和结果的返回。
在Spring里面,每次都拿同一个Mapper Bean,如何在不同的connection下执行呢?
在MapperProxy的代理如下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } |
这里的sqlSession其实是一个SqlSessionTemple对象,在execute方法里面会调用SqlSessionTemple的方法(因为此时的SqlSession就是SqlSessionTemple),以update为例
public Object execute(SqlSession sqlSession, Object[] args) { Object result; if (SqlCommandType.INSERT == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); } else if (SqlCommandType.UPDATE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else if (SqlCommandType.DELETE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else if (SqlCommandType.SELECT == command.getType()) { if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { result = executeForCursor(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else if (SqlCommandType.FLUSH == command.getType()) { result = sqlSession.flushStatements(); } else { throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; } |
而进入SqlSessionTemple的方法其实都是走SqlSessionInterceptor代理
private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SqlSession sqlSession = getSqlSession( SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); try { Object result = method.invoke(sqlSession, args); if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() sqlSession.commit(true); } return result; } catch (Throwable t) { Throwable unwrapped = unwrapThrowable(t); if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { // release the connection to avoid a deadlock if the translator is no loaded. See issue #22 closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); sqlSession = null; Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped); if (translated != null) { unwrapped = translated; } } throw unwrapped; } finally { if (sqlSession != null) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } } |
在SqlSessionInterceptor代理中利用DefaultSqlSessionFactory重新创建了新的SqlSession(对应创建新的Executor),以替换SqlSessionTemple执行,以下是DefaultSqlSessionFactory创建SqlSession的方法
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } |
参考博客