mybatis源码学习之执行过程分析(1)——SqlSessionFactory及SqlSession的创建
来源:互联网 发布:java项目需求文档模板 编辑:程序博客网 时间:2024/05/18 11:16
mybatis源码学习及分析之执行过程分析——SqlSessionFactory及SqlSession的创建
说在前面:首先来看一段JDBC获取数据的代码。
public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/mybatis_study"; Connection conn = DriverManager.getConnection(url, "root", "123456"); PreparedStatement statement = null; ResultSet rs = null; if (conn != null) { System.out.println("get conn"); String sql = "select id,name from user where id=?"; statement = conn.prepareStatement(sql); statement.setInt(1, 1); statement.execute(); rs = statement.getResultSet(); if (rs != null) { System.out.println("get rs"); User user = new User(); for (; rs.next(); ) { user.setId(rs.getInt("id")); user.setName(rs.getString("name")); //... } System.out.println(JSON.toJSONString(user)); } } rs.close(); conn.close(); statement.close(); }
在使用JDBC时,我们所面临的烦恼就是不断的获取Connection、拼接sql、和转换ResultSet。试想一个User有100个字段,那我们的代码就没有可读性了,犯错的概率极大。
mybatis作为一个ORM框架就是为了帮助我们解决这些问题的,包括Connection获取、sql拼接、ResultSet转换为POJO几个方面。接下来的系列文章,会看到mybatis如何处理以上问题的。
分析采用mybati-3.4.1.jar
mybatis的工程结构如图:
与执行流程相关的类主要有:
SqlSessionFactory SqlSessionFactoryBuilder DefaultSqlSessionFactory Configuration DefaultSqlSession MapperProxyFactory MapperProxy MapperMethod CachingExecutor BaseExecutor SimpleExecutor RoutingStatementHandler PreparedStatementHandler ResultMap MappedStatement
下面来看我们程序中的调用流程:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
首先会创建SqlSessionFactory 。在SqlSessionFactoryBuilder调用build(Reader reader)
来创建SqlSessionFactory,并将我们的配置文件(mybatis-config.xml)流包装为Reader传入。
SqlSessionFactoryBuilder.java public SqlSessionFactory build(Reader reader) { return this.build((Reader)reader, (String)null, (Properties)null); }
而build(Reader reader)
调用了build(Reader reader, String environment, Properties properties)
,该方法执行XML文件的解析,并调用build(Configuration config)
创建出默认的SqlSessionFactory 对象。
SqlSessionFactoryBuilder.java public SqlSessionFactory build(Reader reader, String environment, Properties properties) { SqlSessionFactory var5; try { //解析Mybatis-config.xml配置文件中的内容,包括xml文件的校验,以及从<configuration>标签解析mybatis的各项配置,并返回Configuration对象。解析的过程中对Configuration的许多默认参数做了设置,详情见XMLConfigBuilder类的分析。 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); var5 = this.build(parser.parse()); //parser.parse()返回Configuration实例。 } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); //TODO 异常类的分析 try { reader.close(); } catch (IOException var13) { ; } } return var5; } //将Configuration实例传给DefaultSqlSessionFactory public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); //默认创建的SqlSessionFactory为DefaultSqlSessionFactory }
SqlSessionFactory顾名思义就是用来提供各种方法来获取SqlSession。或配置Configuration。
这里主要用到DefaultSqlSessionFactory,其实现了SqlSessionFactory中的openSession等方法,提供了从数据源和连接中获取Session的方法,并提供获取事务工厂和关闭事务的方法。
SqlSessionFactory的创建主要用到了Builder模式:
Configuration担任导演角色。
再来看openSession()
方法:
public SqlSession openSession() { return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false); //可以看到默认的事务隔离级别为空,autoCommit默认为false事务不会自动提交。ExecutorType默认为SIMPLE。 }
可以看出默认是从我们配置的dataSource中获取SqlSession 。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { //获取Environment,即我们在配置文件中用<environments>标签所指定的内容。 Environment environment = this.configuration.getEnvironment(); //获取TransactionFactory工厂,用来创建Transaction TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); //获取事务 tx = transactionFactory.newTransaction(e.getDataSource(), level, autoCommit); //Executor 的创建 Executor executor = this.configuration.newExecutor(tx, execType); //在这里创建了默认的SqlSession var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }
environment就是我们在mybatis-config.xml中配置在 标签内的东西:断点结果如图。
在这里我们配置的是JDBC的事务管理器,所以使用了JDBC的Transaction。
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) { return new JdbcTransaction(ds, level, autoCommit);}
在JdbcTransaction默认使用的是slf4j日志接口,所以我们可以通过配置日志,打印出sql语句。
Executor的创建
在Executor executor = this.configuration.newExecutor(tx, execType);
时进行了Executor的创建,类型为CachingExecutor:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { //两次检查防止executorType为空,默认情况下设置为ExecutorType.SIMPLE executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; //批量 TODO 分析 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); //在这里使用的SimpleExecutor } if (cacheEnabled) { //默认缓存是开启的,所以会创建CachingExecutor executor = new CachingExecutor(executor); } //注册拦截器链(其实就是一个ArrayList) executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
因为cacheEnabled
为true
,所以创建的Executor类型为CachingExecutor。而CachingExecutor中,持有一个delegate类型为SimpleExecutor
。
Interceptor
拦截器链的初始化, executor = (Executor) interceptorChain.pluginAll(executor);
拦截器链是一个ArrayList.
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
SqlSession
接下来看SqlSession。SqlSession中定义了操作数据库的base方法以及对事务的提交和回滚等操作,可以看到mybatis非常灵活,我们可以直接在SqlSession拿到Connection。
同时,SqlSession接口继承自Closeable,而 Closeable extends AutoCloseable
,表示session可以自动被关闭。
例如:我们可以通过拿到Connection并获取操作的表名。
Connection conn = sqlSession.getConnection(); log.info(conn.getCatalog());
//在DefaultSqlSession中,持有Configuration,和Executor的引用。 //所以SqlSession才可以委托Executor具体实现类(例如:CachingExecutor、SimpleExecutor)去执行对应的sql语句。 //而Configuration则提供类型转换、结果解析等信息。public class DefaultSqlSession implements SqlSession { private Configuration configuration; private Executor executor; private boolean autoCommit; private boolean dirty; private List<Cursor<?>> cursorList; ...}
至此,SqlSession创建完成。就可以调用接口中的selectOne()、selectList()去执行查询等操作。
总结:
1.首先会读取mybatis-config.xml配置文件及Mapper.xml映射文件。
2.从以上配置文件中解析各个标签中的信息,并将信息注册到Configuration实例中,同时还会初始化默认的参数。
3.通过DefaultSqlSessionFactoryBuilder#build(Configuration config)
实例化DefaultSqlSessionFactory,并将Configuration传递给它。并通过Configuration中的连接池、事务隔离级别,以及executor和autoCommit等参数实例化SqlSession接口的实现类DefaultSqlSession。
4.DefaultSqlSession具体实现了SqlSession中定义的接口。并通过自己持有的Executor接口,委托具体的Executor去执行sql语句完成具体的CRUD操作。
- mybatis源码学习之执行过程分析(1)——SqlSessionFactory及SqlSession的创建
- MyBatis学习总结(1)----SqlSessionFactory,SqlSession及配置文件
- Mybatis源码分析之SqlSessionFactory,SqlSession和连接池
- mybatis源码分析——SqlSessionFactory实例的产生过程
- MyBatis源码分析——SqlSessionFactory实例的产生过程
- Mybatis 源码分析一、 SqlSessionFactory的创建过程
- mybatis源码学习之执行过程分析(5)——sql执行后ResultSet的处理及结果返回
- SqlSessionFactory创建SqlSession测试mybatis的sql
- mybatis源码分析(1)——SqlSessionFactory实例的产生过程
- mybatis源码学习之执行过程分析(3)——mapper接口的获取
- Mybatis源码分析(二)- SqlSessionFactory和SqlSession详解
- mybatis的探索过程之SqlSessionFactoryBuilder,SqlSessionFactory,SqlSession作用域和生命周期
- myBatis源码学习之SqlSessionFactory
- Mybatis源码分析一(SqlsessionFactory及源码整体结构)
- myBatis源码学习之SqlSession
- mybatis源码学习之执行过程分析(0)——配置文件加载(io包)
- Mybatis源码(二)之Spring整合mybatis创建SqlSession
- Mybatis学习笔记--SqlSessionFactory、SqlSession等
- 关于如何获取url中的参数的值
- Box2d弹性物体的制作
- 正向代理和反向代理
- 为什么我的病不能得到医治?---于宏洁牧师的个人见证
- Notification及桌面小部件的应用(RemoteViews)
- mybatis源码学习之执行过程分析(1)——SqlSessionFactory及SqlSession的创建
- 3. Longest Substring Without Repeating Characters**
- sql之浅谈视图的作用
- EOJ 3177 顺序查找
- 数组操作总结(javascript)
- some basic interview question
- 基于javascript的基本数据结构和查找算法
- OkHttp的介绍及基础使用
- 多线程状态