Mybatis重要对象
SqlSessionFactory
SqlSessionFactory是mybatis的核心对象,是一个数据库连接的抽象,通过他可以执行一次又一次的数据库操作。SqlSessionFactoryBuilder是专门用于构造SqlSessionFactory的工厂,其通过build函数的重载,支持以不同的方式创建SqlSessionFactory:
image其中的InputStream是字节流,Reader是字符流,也可以通过自己定义一个Configuration定义数据库连接的相关信息完成SqlSessionFactory的构造。environment用于指定加载哪种环境的配置:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
...
<dataSource type="POOLED">
...
</environment>
<environment id="production">
<transactionManager type="MANAGED">
...
<dataSource type="JNDI">
...
</environment>
</environments>
SqlSessionFactory的运行周期应该和应用的运行周期一致,同时,没有必要多次创建SqlSessionFactory,实现时可以使用单例。Mybatis提供了一个默认的实现DefaultSqlSessionFactory
在SqlSessionFactory中,通过openSession的重载,提供了创建不同Session的接口:
image
在mybatis-spring包中,将SqlSessionFactory的构造封装到SqlSessionFactoryBean中,默认就被设置成了单例。
imageSqlSession
SqlSessionFactory的产品,当我们在进行一次数据库操作时,都会构造一个Session,把断点定位到DefaultSqlSessionFactory的openSessionFromDataSource方法可以跟踪每一次的数据库操作。SqlSession是非线程安全的,不能被共享。所以,SqlSession的实例不能是静态的,也不能共享到容器中,甚至是类的实例变量也不行。创建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();
}
}
- 从配置中获取环境参数
- 从环境获取事务
- 从环境中获取数据源
- 通过配置构造执行器Executor
- 构造DefaultSqlSession
其中的执行器Executor是最终操作数据库的对象,SqlSession算是把一次数据操作当做一次回话后对外的封装。有三种类型的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;
}
BatchExecutor专门用于执行批量的sql操作,ReuseExecutor会复用statement执行sql操作,而SimpleExecutor就是直接执行sql操作,默认是SIMPLE。最终返回的Executor是一个CachingExecutor,默认情况下Mybatis就开启了执行器缓存,CachingExecutor在查询数据库前先查找缓存,若没找到的话调用传入的Executor对象从数据库查询,并将查询结果存入缓存中。
MappedStatement
MappedStatement是mapper文件中一条操作语句的封装,比如<select/insert/delete>,在XMLMapperBuilder的parsePendingStatements中,通过MapperBuilderAssistant进行构造。
SqlSource
public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}
只有一个方法,就是通过用户传递的参数解析出sql,他有四个实现:
image
其中DynamicSqlSource负责动态sql的解析,RawSqlSource负责静态sql的解析,而它们两者都依赖StaticSqlSource来完成功能,ProviderSqlSource允许用户定制sql的解析。这里静态sql指的是仅包含 '#{}'的sql,而动态sql包含动态标签(if,foreach等),SqlSource最终会被MppedStatement消费。
StatementHandler
直接和数据库交互的接口,它利用了ParameterHandler和ResultSetHandler解析sql参数并组装最后的结果,Executor也就是依赖了这个接口完成数据库操作。
public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
void parameterize(Statement statement)
throws SQLException;
void batch(Statement statement)
throws SQLException;
int update(Statement statement)
throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
其中的prepare用于预编译sql,parameterize则利用了ParameterHandler进行参数的注入。他有这么几个继承的类:
image
- RoutingStatementHandler,这是一个封装类,它不提供具体的实现,只是根据Executor的类型,创建不同的类型StatementHandler
- SimpleStatementHandler,这个类对应于JDBC的Statement对象,用于没有预编译参数的SQL的运行
- PreparedStatementHandler 这个用于预编译参数SQL的运行
- CallableStatementHandler 它将实存储过程的调度
BoundSql
存储Mybatis解析MappedStatement后的sql语句以及用于传递的参数,最终会被StatementHandler消费,最终把带占位符的sql和实参合并成最终的sql是在PreparedStatement中。
Mybatis执行流程
从SqlSessionFactoryBean开始,可以抽象成两条线,一条是mapper.xml的解析,一条是数据库语句的执行
image
SqlSession里两条线建立关联的代码:
image
网友评论