前言
本篇博客适合新手看,对于工作一两年的我们,我们要思考为什么学习mybatis源码,我的回答是,一是为了面试,面试造火箭。二是为了排查工作上遇到的一些问题,三是mybatis为我们做了什么,它的基本原理是什么,我从中可以学习到什么,举一反三。
最后说一句,不要把太多时间花在框架上,框架说白了就是帮你做了一些重复的事情,并且解决了一些额外的问题,而我们要学习的就是解决问题的思想。当然,Spring多花时间学没关系,这个框架很稳,未来几年应该不会被淘汰,哈哈。
1.mybatis加载全局配置文件的过程
开局一张图,出自java知音。
我们发现两个关键的类,SqlSessionFactoryBuilder和XMLConfigBuilder
①SqlSession的概念
官方回答:
SqlSession 的作用类似于一个 JDBC 中的 Connection 对象,代表着一个连接资源的启用。具体而言,它的作用有 3 个:
- 获取 Mapper 接口。
- 发送 SQL 给数据库。
- 控制数据库事务。
SqlSession是一个接口,有两个实现类,DefaultSqlSession 是单线程使用的,而 SqlSessionManager 在多线程环境下使用。
说白了就是一次数据库连接,里面封装了CURD,事务提交和回滚等接口,由两个子类去实现。
SQLSession sqlsession = sqlSessionFactory.openSession();
SqlSessionFactoryBuilder用来构建SqlSessionFactory,SQLSessionFactory用来开启数据库会话
//第4种方法是最常用的,它使用了一个参照了XML文档或更特定的SqlMapConfig.xml文件的Reader实例。
//可选的参数是environment和properties。Environment决定加载哪种环境(开发环境/生产环境),包括数据源和事务管理器。
//如果使用properties,那么就会加载那些properties(属性配置文件),那些属性可以用${propName}语法形式多次用在配置文件中。和Spring很像,一个思想?
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//委托XMLConfigBuilder来解析xml文件,并构建
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
//这里是捕获异常,包装成自己的异常并抛出的idiom?,最后还要reset ErrorContext
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
SQLSessionFactory.openSession()得到SqlSession会话。
因此使用mybatis过程中如果出现了问题,首先看SQLSession会话有没有创建,就去检查一下配置文件的配置信息,是否加载配置文件等等。(其实大部分问题就是配置错误)
②加载配置文件的过程
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
通过XMLConfigBuilder这个构造器来构造出一个Configuration对象,就代表一个xml文件。
//解析配置
public Configuration parse() {
//如果已经解析过了,报错
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// <?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>
//根节点是configuration
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析配置
private void parseConfiguration(XNode root) {
try {
//分步骤解析
//issue #117 read properties first
//1.properties
propertiesElement(root.evalNode("properties"));
//2.类型别名
typeAliasesElement(root.evalNode("typeAliases"));
//3.插件
pluginElement(root.evalNode("plugins"));
//4.对象工厂
objectFactoryElement(root.evalNode("objectFactory"));
//5.对象包装工厂
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory&#