SqlSessionFactoryBuilder、SqlSessionFactory 和 SqlSession

2022-08-19 20:21:18 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

SqlSessionFactoryBuilder、SqlSessionFactory 和 SqlSession

  • SqlSessionFactoryBuilder
  • SqlSessionFactory
  • SqlSession
    • 执行语句方法
    • 批量立即更新方法
    • 事务控制方法
    • 本地缓存
    • 确保 SqlSession 被关闭

使用 MyBatis 的主要 Java 接口就是 SqlSession。你可以通过这个接口来执行命令,获取映射器和管理事务。我们会概括讨论一下 SqlSession 本身,但是首先我们还是要了解如何获取一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对象包含创建 SqlSession 实例的所有方法。而 SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 创建的,它可以从 XML、注解或手动配置 Java 代码来创建 SqlSessionFactory。

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 有五个 build() 方法,每一种都允许你从不同的资源中创建一个 SqlSession 实例。

代码语言:javascript复制
SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String env, Properties props)
SqlSessionFactory build(Configuration config)

第一种方法是最常用的,它使用了一个参照了 XML 文档或上面讨论过的更特定的 mybatis-config.xml 文件的 Reader 实例。可选的参数是 environment 和 properties。environment 决定加载哪种环境,包括数据源和事务管理器。如果你调用了参数有 environment 的 build 方法,那么 MyBatis 将会使用 configuration 对象来配置这个 environment。当然,如果你指定了一个不合法的 environment,你就会得到错误提示。如果你调用了不带 environment 参数的 build 方法,那么就使用默认的 environment。

如果你调用了参数有 properties 实例的方法,那么 MyBatis 就会加载那些 properties(属性配置文件),并在配置中可用。那些属性可以用${propName} 语法形式多次用在配置文件中。

如果一个属性存在于这些位置,那么 MyBatis 将会按照下面的顺序来加载它们:

  1. 首先读取在 properties 元素体中指定的属性;
  2. 其次,读取从 properties 元素的类路径 resource 或 url 指定的属性,且会覆盖已经指定了的重复属性;
  3. 最后,读取作为方法参数传递的属性,且会覆盖已经从 properties 元素体和 resource 或 url 属性中加载了的重复属性。

最后一个 build 方法的参数为 Configuration 实例。configuration 类包含你可能需要了解 SqlSessionFactory 实例的所有内容。Configuration 类对于配置的自查很有用,它包含查找和操作 SQL 映射(当应用接收请求时便不推荐使用)。作为一个 Java API 的 configuration 类具有所有配置的开关,这些你已经了解了。这里有一个简单的示例,教你如何手动配置 configuration 实例,然后将它传递给 build() 方法来创建 SqlSessionFactory。

代码语言:javascript复制
DataSource dataSource = BaseDataTest.createBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setEnhancementEnabled(true);
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.getTypeAliasRegistry().registerAlias(Post.class);
configuration.getTypeAliasRegistry().registerAlias(Author.class);
configuration.addMapper(BoundBlogMapper.class);
configuration.addMapper(BoundAuthorMapper.class);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);

现在你就获得一个可以用来创建 SqlSession 实例的SqlSessionFactory 了!

SqlSessionFactory

SqlSessionFactory 有六个方法创建 SqlSession 实例。通常来说,当你选择这些方法时你需要考虑以下几点:

  1. 事务处理:我需要在 session 使用事务或者使用自动提交功能(auto-commit)吗?(通常意味着很多数据库和/或 JDBC 驱动没有事务)
  2. 连接:我需要依赖 MyBatis 获得来自数据源的配置吗?还是使用自己提供的配置?
  3. 执行语句:我需要 MyBatis 复用预处理语句和/或批量更新语句(包括插入和删除)吗?

基于以上需求,有下列已重载的多个 openSession() 方法供使用。

代码语言:javascript复制
SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
SqlSession openSession(ExecutorType execType, Connection connection)
Configuration getConfiguration();

默认的 openSession()方法没有参数,它会创建有如下特性的 SqlSession:

  1. 会开启一个事务(也就是不自动提交)。
  2. 将从由当前环境配置的 DataSource 实例中获取 Connection 对象。 事务隔离级别将会使用驱动或数据源的默认设置。
  3. 预处理语句不会被复用,也不会批量处理更新。

这些方法大都是可读性强的。向 autoCommit 可选参数传递 true 值即可开启自动提交功能。若要使用自己的 Connection 实例,传递一个 Connection 实例给 connection 参数即可。还有一个可能对你来说是新见到的参数,就是 ExecutorType。这个枚举类型定义了三个值:

  1. ExecutorType.SIMPLE:这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
  2. ExecutorType.REUSE:这个执行器类型会复用预处理语句。
  3. ExecutorType.BATCH:这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行,必要时请把它们区分开来以保证行为的易读性。

SqlSession

在 SqlSession 类中有超过 20 个方法,所以将它们组合成易于理解的分组。

执行语句方法

这些方法被用来执行定义在 SQL 映射的 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以是原生类型(自动装箱或包装类)、JavaBean、POJO 或 Map。

代码语言:javascript复制
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)

selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象或 null 值。如果返回值多于一个,那么就会抛出异常。selectMap 稍微特殊一点,因为它会将返回的对象的其中一个属性作为 key 值,将对象作为 value 值,从而将多结果集转为 Map 类型值。因为并不是所有语句都需要参数,所以这些方法都重载成不需要参数的形式。

最后,还有 select 方法的三个高级版本,它们允许你限制返回行数的范围,或者提供自定义结果控制逻辑,这通常在数据集合庞大的情形下使用。

代码语言:javascript复制
<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler<T> handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)

RowBounds 参数会告诉 MyBatis 略过指定数量的记录,还有限制返回结果的数量。

ResultHandler 参数允许你按你喜欢的方式处理每一行。你可以将它添加到 List 中、创建 Map 和 Set,或者丢弃每个返回值都可以,它取代了仅保留执行语句过后的总结果列表的死板结果。你可以使用 ResultHandler 做很多事,并且这是 MyBatis 自身内部会使用的方法,以创建结果集列表。

它的接口很简单。

代码语言:javascript复制
package org.apache.ibatis.session;
public interface ResultHandler<T> { 
   
  void handleResult(ResultContext<? extends T> context);
}

ResultContext 参数允许你访问结果对象本身、被创建的对象数目、以及返回值为 Boolean 的 stop 方法,你可以使用此 stop 方法来停止 MyBatis 加载更多的结果。

使用 ResultHandler 的时候需要注意以下两种限制:

  1. 从被 ResultHandler 调用的方法返回的数据不会被缓存。
  2. 当使用结果映射集(resultMap)时,MyBatis 大多数情况下需要数行结果来构造外键对象。如果你正在使用 ResultHandler,你可以给出外键(association)或者集合(collection)尚未赋值的对象。

批量立即更新方法

有一个方法可以刷新(执行)存储在 JDBC 驱动类中的批量更新语句。当你将 ExecutorType.BATCH 作为 ExecutorType 使用时可以采用此方法。

代码语言:javascript复制
List<BatchResult> flushStatements();

事务控制方法

控制事务作用域有四个方法。当然,如果你已经设置了自动提交或你正在使用外部事务管理器,这就没有任何效果了。然而,如果你正在使用 JDBC 事务管理器,由Connection 实例来控制,那么这四个方法就会派上用场:

代码语言:javascript复制
void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)

默认情况下 MyBatis 不会自动提交事务,除非它侦测到有插入、更新或删除操作改变了数据库。如果你已经做出了一些改变而没有使用这些方法,那么你可以传递 true 值到 commit 和 rollback 方法来保证事务被正常处理(注意,在自动提交模式或者使用了外部事务管理器的情况下设置 force 值对 session 无效)。很多时候你不用调用 rollback(),因为 MyBatis 会在你没有调用 commit 时替你完成回滚操作。然而,如果你需要在支持多提交和回滚的 session 中获得更多细粒度控制,你可以使用回滚操作来达到目的。

本地缓存

Mybatis 使用到了两种缓存:本地缓存(local cache)和二级缓存(second level cache)。

每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询语句本身都会被保存在本地缓存中,那么,相同的查询语句和相同的参数所产生的更改就不会二度影响数据库了。本地缓存会被增删改、提交事务、关闭事务以及关闭 session 所清空。

默认情况下,本地缓存数据可在整个 session 的周期内使用,这一缓存需要被用来解决循环引用错误和加快重复嵌套查询的速度,所以它可以不被禁用掉,但是你可以设置 localCacheScope=STATEMENT 表示缓存仅在语句执行时有效。注意,如果 localCacheScope 被设置为 SESSION,那么 MyBatis 所返回的引用将传递给保存在本地缓存里的相同对象。对返回的对象(例如 list)做出任何更新将会影响本地缓存的内容,进而影响存活在 session 生命周期中的缓存所返回的值。因此,不要对 MyBatis 所返回的对象作出更改,以防后患。

你可以随时调用以下方法来清空本地缓存:

代码语言:javascript复制
void clearCache()

确保 SqlSession 被关闭

代码语言:javascript复制
void close()

(关于使用映射器章节请参考官网)


  1. 本文来源( http://www.mybatis.org/mybatis-3/zh/index.html )

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/136337.html原文链接:https://javaforall.cn

0 人点赞