通常我们如果自己写建立数据库连接的代码的时候,都会这么写
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, email);
result = pstmt.executeQuery();
而Mybatis是怎么封装,又是怎么进行预编译的呢,今天就一文让你理解Mybatis的原理
我们之前一篇文章《MyBatis源码分析(一)基本请求流程》讲了Mybatis执行的基本流程,包括Plugin插件。
其实在执行过程中,所有的sql语句都要经过执行器Executor。执行器创建的源码如下:
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;
}
可以看到创建的执行器有三种,分别是
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
以上的三个Executor都有同一个父类:BaseExecutor,在BaseExecutor的query方法中,调用了三个子类的doQuery方法,update方法中,调用了三个子类的doUpdate方法,这是用了模板方法设计模式。
SqlSession是一次数据库连接,在Mybatis中,是通过如下方式创建的:
同时也可以看到,一个SqlSession对应创建一个新的执行器Executor。这也是为什么我们上面说ReuseExecutor没有什么用处的原因,在Mybatis中一个sql语句就会创建一个SqlSession,创建一个执行器Executor,ReuseExecutor就算缓存了PrepareStatement也用不上。
在执行sql的时候,会调用到SqlSessionTemplate,这是一个模板方法的类。在invoke方法执行完后,会调用finally方法关闭连接:
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
这个方法中调用了session.close(),里面又调用了executor.close()方法去关闭SqlSession,Executor从而关闭SqlSession,释放连接。
SimpleExecutor是Mybatis默认使用的执行器,其doQuery方法如下:
@Override
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());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
可以看到里面限制性的prepareStatement方法,然后又执行了query方法。
prepareStatement方法里面其实就是封装了我们手动创建PrepareStatement的时候的conn.prepareStatement方法,先去进行预编译,预编译完成后,在调用query方法执行。
由此可见Mybatis底层还是用的我们自己创建Statement并执行sql语句的方法。
在Mybatis中,我们都要写xml文件,例如这样一段xml写的sql:
<select id="selectByIdList" resultMap="BaseResultMap" parameterType="Long" >
select
<include refid="Base_Column_List" />
from table_1
where id in
<foreach collection="list" item="status_id" open="(" close=")" separator=",">
#{id}
foreach>
select>
Mybatis是怎么把这样的语句解析成sql语句的呢,就是通过SqlNode,SqlNode是一个接口类,它有很多子类
例如IfSqlNode就是用来解析Mybatis文件下面的
本篇文章主要向你介绍了执行sql的一些关键节点:
在读了这篇文章后,你是不是对Mybatis的原理理解地非常深入了呢?为了让你更好的进行开发工作,博主创建了一篇专栏教你精通使用在工作过程中的各种工具:《精通java开发工具》快来提升你的工作效率吧。