Mybatis技术(四) 从配置读取到打开连接的源码分析
来源:互联网 发布:最好的流程优化方法 编辑:程序博客网 时间:2024/05/17 20:34
1. 准备工作
编写测试代码(具体请参考《Mybatis入门示例》),设置断点,以Debug模式运行,具体代码如下:
String resource = "mybatis.cfg.xml"; Reader reader = Resources.getResourceAsReader(resource); SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader); SqlSession session = ssf.openSession();
2.源码分析
我们此次就对上面的代码进行跟踪和分析,let's go。
首先我们按照顺序先看看第一行和第二行代码,看看它主要完成什么事情:
String resource = "mybatis.cfg.xml"; Reader reader = Resources.getResourceAsReader(resource);
读取Mybaits的主配置配置文件,并返回该文件的输入流,我们知道Mybatis所有的SQL语句都写在XML配置文件里面,所以第一步就需要读取这些XML配置文件,这个不难理解,关键是读取文件后怎么存放。
我们接着看第三行代码(如下),该代码主要是读取配置文件流并将这些配置信息存放到Configuration类中。
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactoryBuilder的build的方法如下:
public SqlSessionFactory build(Reader reader) { return build(reader, null, null); }
其实是调用该类的另一个build方法来执行的,具体代码如下:
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. } } }
我们重点看一下里面两行:
//创建一个配置文件流的解析对象XMLConfigBuilder,其实这里是将环境和配置文件流赋予解析类 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); // 解析类对配置文件进行解析并将解析的内容存放到Configuration对象中,并返回SqlSessionFactory return build(parser.parse());
这里的XMLConfigBuilder初始化其实调用的代码如下:
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { super(new Configuration()); ErrorContext.instance().resource("SQL Mapper Configuration"); this.configuration.setVariables(props); this.parsed = false; this.environment = environment; this.parser = parser; }
XMLConfigBuilder的parse方法执行代码如下:
public Configuration parse() { if (parsed) { throw new BuilderException("Each MapperConfigParser can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; }
析的内容主要是在parseConfiguration方法中,它主要完成的工作是读取配置文件的各个节点,然后将这些数据映射到内存配置对象Configuration中,我们看一下parseConfiguration方法内容:
private void parseConfiguration(XNode root) { try { typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); propertiesElement(root.evalNode("properties")); settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
最后的build方法其实是传入配置对象进去,创建DefaultSqlSessionFactory实例出来. DefaultSqlSessionFactory是SqlSessionFactory的默认实现.
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
最后我们看一下第四行代码:
SqlSession session = ssf.openSession();
通过调用DefaultSqlSessionFactory的openSession方法返回一个SqlSession实例,我们看一下具体是怎么得到一个SqlSession实例的。首先调用openSessionFromDataSource方法。
public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
下面我们看一下openSessionFromDataSource方法的逻辑:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Connection connection = null; try { //获取配置信息里面的环境信息,这些环境信息都是包括使用哪种数据库,连接数据库的信息,事务 final Environment environment = configuration.getEnvironment(); //根据环境信息关于数据库的配置获取数据源 final DataSource dataSource = getDataSourceFromEnvironment(environment); //根据环境信息关于事务的配置获取事务工厂 TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); connection = dataSource.getConnection(); if (level != null) { //设置连接的事务隔离级别 connection.setTransactionIsolation(level.getLevel()); } //对connection进行包装,使连接具备日志功能,这里用的是代理。 connection = wrapConnection(connection); //从事务工厂获取一个事务实例 Transaction tx = transactionFactory.newTransaction(connection, autoCommit); //从配置信息中获取一个执行器实例 Executor executor = configuration.newExecutor(tx, execType); //返回SqlSession的一个默认实例 return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeConnection(connection); throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
传入参数说明:
(1)ExecutorType:执行类型,ExecutorType主要有三种类型:SIMPLE, REUSE, BATCH,默认是SIMPLE,都在枚举类ExecutorType里面。
(2)TransactionIsolationLevel:事务隔离级别,都在枚举类TransactionIsolationLevel中定义。
(3)autoCommit:是否自动提交,主要是事务提交的设置。
DefaultSqlSession是SqlSession的实现类,该类主要提供操作数据库的方法给开发人员使用。
这里总结一下上面的过程,总共由三个步骤:
步骤一:读取Ibatis的主配置文件,并将文件读成文件流形式(InputStream)。
步骤二:从主配置文件流中读取文件的各个节点信息并存放到Configuration对象中。读取mappers节点的引用文件,并将这些文件的各个节点信息存放到Configuration对象。
步骤三:根据Configuration对象的信息获取数据库连接,并设置连接的事务隔离级别等信息,将经过包装数据库连接对象SqlSession接口返回,DefaultSqlSession是SqlSession的实现类,所以这里返回的是DefaultSqlSession,SqlSession接口里面就是对外提供的各种数据库操作。
- Mybatis技术(四) 从配置读取到打开连接的源码分析
- 【mybatis源码分析】原理分析之一:从JDBC到Mybatis
- mybatis 从入门到精通(四)
- Mongoose6.0源码分析(1)-从一个example开始到读取数据
- thinkphp3.1.3源码分析(2)配置项的读取
- MyBatis连接池源码分析
- TensorFlow 从入门到精通(四):CIFAR10 多 GPU 版本例程源码分析
- Flume 1.7 源码分析(四)从Source写数据到Channel
- SpringMVC提高篇(四):从Servlet到DispatcherServlet源码分析
- 从HashMap到LruCache的源码分析
- 从HashMap到LruCache的源码分析
- log4j 从配置到源码分析和测试(1)
- 【mybatis源码分析】原理分析之四:一次SQL查询的源码分析
- Mybatis源码分析-配置模块
- mybatis 的源码分析
- MapReduce(十五): 从HDFS读取文件的源码分析
- 从创建四家技术公司中学到的事情
- 从创建四家技术公司中学到的事情 .
- dynamic-insert,dynamic-update能够性能上的少许提升
- 为什么我的GetClientRect()得到的全是0
- Linux gcc编译器的使用
- TCP连接、Http连接与Socket连接
- 在Win8下配置Python和Django
- Mybatis技术(四) 从配置读取到打开连接的源码分析
- 快速排序及其中的两种划分中枢点的方法
- 使用navigator.userAgent来判断浏览器类型
- FilterDispatcher已被标注为过时
- 转载 VB.NET编程调用迅雷下载文件
- java实现简易画图板 & 曲线的画法 & 总结
- Mybatis技术(五)Mybatis调用存储过程
- 如何将一个Activity设置成窗口的样式
- 数据库实例