mybatis
Mybatis 启动流程解析
mybatis分析
上面这篇文章的分析挺好的(主要是图画的好,不会画图,很尴尬,盗几张图)。
从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:
- SqlSessionFactory SqlSession 工厂,全局唯一(单库情况)
- Configuration MyBatis所有的配置信息都维持在Configuration对象之中。
- SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
- Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
- StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
- ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
- ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
- TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
- MappedStatement MappedStatement维护了一条
xml启动
mybatis 的启动单独使用时通过一个核心配置xml + n个mapper.xml 的
与 springboot 集成的时候,通常只剩下 n个mapper.xml 了(不用xml也行,但是通常还是会使用xml来定义复杂一点的语句)。
我们还是从xml分析
基础概念
1. SqlSessionFactory
SqlSession 工厂,全局唯一(单数据源的情况下),启动实际上就是构建 SqlSessionFactory(但是配置信息全部在 Configuration)
2. SqlSession
跟数据库交互的操作都是基于这个类(即使是 Dao 接口,也是 getMapper 获取到的动态代理)
3. Configuration
核心配置类,所有 mybatis 相关的配置和解析出来的信息都在这里
入门
使用xml
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
不使用xml
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
上面就是启动,获取 SqlSessionFactory 实例后就可以继续获取 SqlSession 进行数据操作了
数据操作
SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
上面两种操作方式,通常使用的是第二种,并且这部分操作都会进行封装(跟spring 集成的时候),在业务里面直接获取 Dao
接口进行操作(不需要实现类).
入口分析从 SqlSessionFactoryBuilder 开始
SqlSessionFactoryBuilder
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
重点就是这个方法,还有一个重载方法,参数类型是 InputStream,根据 api 构建,就可以猜到 XMLConfigBuilder 经过 parse 后,就是 Configuration 实例了
获取 Configuration 实例后
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
// 构建 SqlSessionFactory ,只是将 Configuration 对象传过来的
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
可以看到 SqlSessionFactory 的实现就是 DefaultSqlSessionFactory
接下来我们看看解析细节
XMLConfigBuilder
这里的就是就是核心配置文件
示例
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
// 当parse 完成后,返回 configuration,这个类是核心类,有所有的信息
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
我们不去细看xml解析语法(在构造这个实例的时候就已经解析成一个 Dom 对象了)
这里重要的是 parseConfiguration(parser.evalNode("/configuration"));
,直接就能猜到是解析 configuration 节点
// 解析 xml 配置文件
// 解析完成后,所有的信息都在 Configuration 对象上
private