结构图
mybatis核心组件之间的关系可以用下图表示:
其中类名前加个”I“表示接口
SqlSessionFactoryBuilder
从图上可以看到,除了Configuration外,每个类的类名都包含一个”SqlSession“,从结构图中也可以看到,我们最终的目标就是为了创建SqlSession,SqlSession可以暂时理解为jdbc中的Connection,通过SqlSession执行sql。
SqlSessionFactoryBuilder顾名思义,是SqlSessionFactory的构建器。
SqlSession唯一的职责就是构建SqlSessionFactory。构建方式也是多种多样的,可以传入配置文件的Reader对象、输入流,或者直接传入一个封装好的配置类。
Configuration
Configuration类在上面的SqlSessionFactoryBuilder中就已经露面了,这个类中有很多配置项。
这些配置项在启动的时候,会一次性初始化好。(或通过代码、或通过配置文件)
可以看下Configuration与SqlSessionFactory的关系。
(DefaultSqlSessionFactory是SqlSessionFactory的一个实现类,后面会说到)
DefaultSqlSessionFactory的构造函数只有一个,Configuration作为配置类是必传的。SqlSessionFactory通常与数据源相对应,一个数据源只有一个Factory实例,所以Configuration也同样会常驻内存。
回想初遇mybatis,还没有用上springboot时,常常需要维护一个xml配置文件。
这个配置文件的所有配置项都与Configuration一 一对应。
SqlSessionFactory
SqlSessionFactory是一个接口,有两个实现类SqlSessionManager与DefaultSqlSessionFactory。
职责单一,仅仅用来创建SqlSession。
public interface SqlSessionFactory {
//8个方法可以用来创建SqlSession实例
SqlSession openSession();
//自动提交
SqlSession openSession(boolean autoCommit);
//连接
SqlSession openSession(Connection connection);
//事务隔离级别
SqlSession openSession(TransactionIsolationLevel level);
//执行器的类型
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
创建过程:
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);
//然后产生一个DefaultSqlSession
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();
}
}
大概逻辑如下:
1、通过事务工厂产生一个事务
事务对象有如下部分组成
数据连接对象、数据源、事务隔离信息、是否自动提交。
数据连接对象(Connection)可以没有,因为可以从数据源中获取。
所以我们可以看到,mybatis从配置类中获取到了Environment对象,并拿到了数据源。
2、生成执行器
得到事务对象后,包装一下就成了Executor(执行器)。
Executor负责sql最终的执行。
3、创建SqlSession
SqlSession
终于到主角了,SqlSession。
SqlSession也是接口,只有两个实现类,SqlSessionManager以及DefaultSessionManager。
比较常用的是DefaultSessionManager。
其实从上面的创建过程就可以看出SqlSession的主要成分了。
new DefaultSqlSession(configuration, executor, autoCommit);
配置类、执行器,最后一个参数表示是否自动提交事务。
意图相当明显了,这分明是让SqlSession做最关键的活——调用executor执行sql语句。
sql语句哪里来?
SqlSession开放的方法接口可以看出,mybatis把常见的一些数据库操作做了封装,不出意外SqlSession就是接待sql的窗口。
我们写一个sql
public interface RoleMapper {
public Role getRole(@Param("id") Long id);
}
对应的xml
<select id="getRole" parameterType="long" resultMap="roleMap">
select
id,role_name as roleName,note from role where id=#{id}
</select>
最终会调用SqlSession的第二个方法
<T> T selectOne(String statement, Object parameter);
statement并不是指最终的sql,而是与mybatis中的mapper的方法相对应(mapper接口)。
第二参数通常是map或者pojo对象。比如上述案例中虽然传递只有一个参数id,mybatis也会封装成一个map。见下图:
通过mapper的方法名找到MappedStatement,并交给执行器executor执行sql。
这一篇算是总览,后面会根据一些具体的实现再做总结。
如有错误,欢迎批评指正!