[框架学习——MyBatis 3] SqlSession 的前生今世(上)
在持久层中使用 MyBatis 框架,核心操作就是对 SqlSession 实例对象的操作。下面就详细探索一下 SqlSession 对象的创建及使用。
想要获得一个 SqlSession 实例,首先你要有一个 SqlSessionFactory 实例,而要获得 SqlSessionFactory 实例,需要有一个 SqlSessionFactoryBuilder 对象。MyBatis 就为我们提供了这样一个类,来创建我们需要的 SqlSessionFactory 实例,并用来创建 SqlSession 实例。
注意,如果使用 Spring 等依赖注入容器, SqlSession 实例的创建会全部交给容器进行管理,这样就不再需要手动创建和管理 SqlSessionFactoryBuilder 和 SqlSessionFactory 了。本文暂不考虑这部分内容。
先来看一下 SqlSessionFactoryBuilder 的方法签名:
1 build(Reader) 2 build(Reader, String) 3 build(Reader, Properties) 4 build(Reader, String, Properties) 5 build(InputStream) 6 build(InputStream, String) 7 build(InputStream, Properties) 8 build(InputStream, String, Properties) 9 build(Configuration)
这些方法均会返回一个 SqlSessionFactory 。虽然看上去很多,但实际上只有三个主要方法,其他的都是相应的重载方法。这三个方法接收的参数主要是 Reader ,InputStream ,Configuration ,对应于不同配置文件的读取来源。我们来看一下 build 方法体中的内容:
1 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { 2 try { 3 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); 4 return build(parser.parse()); 5 } catch (Exception e) { 6 throw ExceptionFactory.wrapException("Error building SqlSession.", e); 7 } finally { 8 ErrorContext.instance().reset(); 9 try { 10 inputStream.close(); 11 } catch (IOException e) { 12 // Intentionally ignore. Prefer previous error. 13 } 14 } 15 }
这里以 InputStream 为例, Reader 与之类似。这个方法的作用就是将输入流连接的 XML 文件和自定义的环境 environment 、属性 properties 封装成一个 XMLConfigBuilder 对象,再调用该对象的 parse 方法将 XML 及自定义环境和属性转换成一个 Configuration 对象。其中,environment 变量对应配置文件中 <enviroments> 标签下的内容,而 properties 变量则对应配置文件中 <properties> 标签下的内容。关于配置文件,在以后的文章中将详细介绍。
代码 build(parser.parse()) 调用的是 build(Configuration) 这个方法,从这里我们可以看出,SqlSessionFactoryBuilder 的这些方法的最终目的就是生成一个 Configuration 对象,其内部包含所有创建 SqlSessionFactory 所需的配置信息,然后用这些配置信息返回一个 用来提供 SqlSession 实例的 SqlSessionFactory 实例。
下面是通过 XML 配置文件获得 SqlSessionFactory 的代码示例:
1 String resource = "mybatis-config.xml"; 2 // 使用 MyBatis 提供的 Resource 工具类来获取 xml 文件流 3 InputStream in = Resources.getResourceAsStream(resource); 4 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
当然,你可以编写代码直接创建 Configuration 类的实例并传给 SqlSessionFactoryBuilder 来生产 SqlSessionFactory ,这里暂时先不做说明。
SqlSessionFactoryBuilder 的本质就是封装了一系列方便创建 SqlSessionFactory 这个重要实例的方法,因此当获得了会话工厂 SqlSessionFactory 之后,SqlSessionFactoryBuilder 的使命就完成了,可以结束它这短暂的一生了。文档中建议一旦获得会话工厂中就废弃 SqlSessionFactoryBuilder 以节省系统资源,它的命运也是够悲惨的。
(注:这里涉及到 XML 文件等流的关闭操作,因此尽快释放资源是明智的选择,SqlSessionFactoryBuilder 建议在方法域中使用。)
那么,接下来的重心就转移到 SqlSessionFactory 的身上了。这家伙可了不得,一旦被创建出来,将与天地同寿,永远贮存在内存中以供使用,虽然常常一直隐匿于幕后,却是 MyBatis 中非常重要的实例对象。(通常在应用域中以单例或静态单例方式使用。)
实际上 SqlSessionFactory 是一个抽象的接口,它规定的方法如下:
1 openSession() 2 openSession(boolean) 3 openSession(Connection) 4 openSession(TransactionIsolationLevel) 5 openSession(ExecutorType) 6 openSession(ExecutorType, boolean) 7 openSession(ExecutorType, TransactionIsolationLevel) 8 openSession(ExecutorType, Connection) 9 getConfiguration()
除了最后一个方法用来获得 Configuration 对象之外,其实都是 openSession 这个方法的重载,目的就是获得具有不同属性的 SqlSession 实例对象。再回头看一眼(最后一眼) SqlSessionFactoryBuilder 中最后一个方法,
1 public SqlSessionFactory build(Configuration config) { 2 return new DefaultSqlSessionFactory(config); 3 }
我们可以明确地看到,实际上返回的是 DefaultSqlSessionFactory 这个具体的实现类,同时我们也能看出该类将持有 Configuration 对象的引用。
传递的参数基本上是 ExecuterType 、Connection 、TransactionIsolationLevel 、boolean 的多种组合。
- boolean 值指定是否使用事务的自动提交,默认为 false ,即开启事务但不会自动提交,需要手动 commit ;
- Connection 是手动给定一个数据库连接,当不给定时默认在配置的 data source 中自动获取;
- TransactionIsolationLevel 是一个枚举类,包含了五种隔离等级,默认是与数据库驱动或 data source 默认配置相同;
- ExecuterType 也是一个枚举类,包含 SIMPLE(default) 、REUSE 、BATCH 三个值,REUSE 表示会重用 PreparedStatements ,BATCH 表示批处理更新操作。
可以看出,MyBatis 3 (不同与之前的版本)将数据库相关的操作都整合到了 Session 域中,只需要在创建 Session 的时候将参数指定好就可以了,不需要再单独设置。这也是 SqlSessionFactory 便捷之处。

浙公网安备 33010602011771号