Mybatis 之 SqlSessionFactory

来源:互联网 发布:机房网络机柜拼接 编辑:程序博客网 时间:2024/05/18 12:01

基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

而SqlSession是由SqlSessionFactory创建,所以SqlSession的创建过程是SqlSessionFactoryBuilder -->SqlSessionFactory -->SqlSession.

我们通过代码简单回顾一下SQLSession实例的创建过程。

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();


一.从 XML 文件中构建 SqlSessionFactory 的实例,建议使用类路径下的资源文件进行配置。但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件。

String resource = "mybatis.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

XML 配置文件(mybatis.xml)中包含了对 MyBatis 系统的核心设置,这里先给出一个简单的示例

<?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="com.mysql.jdbc.Driver" />                <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />                <property name="username" value="root" />                <property name="password" value="root" />            </dataSource>        </environment>    </environments>    <mappers>               <mapper resource="com/oumyye/mapping/userMapping.xml"/>     </mappers></configuration>


二。直接从 Java 程序而不是 XML 文件中创建 configuration,或者创建你自己的 configuration 构建器,MyBatis 也提供了完整的配置类,提供所有和 XML 文件相同功能的配置项。

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();TransactionFactory transactionFactory = new JdbcTransactionFactory();Environment environment = new Environment("development", transactionFactory, dataSource);Configuration configuration = new Configuration(environment);configuration.addMapper(BlogMapper.class);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

该例中,configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射语句的注解从而避免了 XML 文件的依赖。不过,由于 Java 注解的一些限制加之某些 MyBatis 映射的复杂性,XML 映射对于大多数高级映射(比如:嵌套 Join 映射)来说仍然是必须的。有鉴于此,如果存在一个对等的 XML 配置文件的话,MyBatis 会自动查找并加载它(这种情况下, BlogMapper.xml 将会基于类路径和 BlogMapper.class 的类名被加载进来)。


三。从 SqlSessionFactory 中获取 SqlSession

SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

SqlSession session = sqlSessionFactory.openSession();try {  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);} finally {  session.close();}

上面这种方式对于使用旧版本 MyBatis 的用户来说也比较熟悉,不过现在有了一种更直白的方式。使用对于给定语句能够合理描述参数和返回值的接口(比如说BlogMapper.class),你现在不但可以执行更清晰和类型安全的代码,而且还不用担心易错的字符串字面值以及强制类型转换。例如:

SqlSession session = sqlSessionFactory.openSession();try {  BlogMapper mapper = session.getMapper(BlogMapper.class);  Blog blog = mapper.selectBlog(101);} finally {  session.close();}


SqlSessionFactoryBuilder

我们首先来看看SqlSessionFactoryBuilder这个类。它放置在package org.apache.ibatis.session包中。

public class SqlSessionFactoryBuilder {  public SqlSessionFactory build(Reader reader) {    return build(reader, null, null);  }  public SqlSessionFactory build(Reader reader, String environment) {    return build(reader, environment, null);  }  public SqlSessionFactory build(Reader reader, Properties properties) {    return build(reader, null, properties);  }  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.      }    }  }  public SqlSessionFactory build(InputStream inputStream) {    return build(inputStream, null, null);  }  public SqlSessionFactory build(InputStream inputStream, String environment) {    return build(inputStream, environment, null);  }  public SqlSessionFactory build(InputStream inputStream, Properties properties) {    return build(inputStream, null, properties);  }  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {    try {      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);      return build(parser.parse());    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error building SqlSession.", e);    } finally {      ErrorContext.instance().reset();      try {        inputStream.close();      } catch (IOException e) {        // Intentionally ignore. Prefer previous error.      }    }  }      public SqlSessionFactory build(Configuration config) {    return new DefaultSqlSessionFactory(config);  }}

我们可以看到这个类用很多的构造方法,但主要分为三大类:

1、通过读取字符流(Reader)的方式构件SqlSessionFactory。

2、通过字节流(InputStream)的方式构件SqlSessionFacotry。

3、通过Configuration对象构建SqlSessionFactory。

第1、2种方式是通过配置文件方式,第3种是通过Java代码方式。

build方法返回SqlSessionFactory接口的实现对象DefaultSqlSessionFactory。


SqlSessionFactory

SqlSessionFactory就是用来创建SqlSession实例:

public interface SqlSessionFactory {  SqlSession openSession();  SqlSession openSession(boolean autoCommit);  SqlSession openSession(Connection connection);  SqlSession openSession(TransactionIsolationLevel level);  SqlSession openSession(ExecutorType execType);  SqlSession openSession(ExecutorType execType, boolean autoCommit);  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);  SqlSession openSession(ExecutorType execType, Connection connection);  Configuration getConfiguration();}

这么多的openSession重载方法,都是通过传入不同的参数构造SqlSession实例,有通过设置事务是否自动提交"autoCommit",有设置执行器类型"ExecutorType"来构造的,还有事务的隔离级别等等。最后一个方法就告诉我们可以通过SqlSessionFactory来获取Configuration对象。


DefaultSqlSessionFactory

DefaultSqlSessionFactory是SqlSessionFactory的实现类。对SqlSessionFactory的具体实现,除了以上方法之外,还包括了:openSessionFromDataSource、openSessionFromConnection、getTransactionFactoryFromEnvironment、closeTransaction。

private final Configuration configuration;
看到configuration被final关键词修饰,很显然Configuration应该是存在于MyBatis的整个生命周期,那么意味着它应该是有且仅有一个实例的,而final关键字修饰的变量字段就代表它是不可变对象,这也恰好能解释说明官方所说的SqlSessionFactory应该是单例的。

DefaultSqlSessionFactory并没有直接实现这8个openSession方法而是调用另外两个新的方法,这8个openSession方法实际上分为两大类:一个是从数据源中获取SqlSession,一个是从Connection中获取SqlSession(包含Connection参数的那两个构造函数)。


先看从数据源中获取SqlSession:

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    Transaction tx = null;    try {      final Environment environment = configuration.getEnvironment();      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);      final Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {      closeTransaction(tx); // may have fetched a connection so lets call close()      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {      ErrorContext.instance().reset();    }  }


我们可以看到返回SqlSession的实例DefaultSqlSession对象。

另外一个方法是从Connection中获取SqlSession:

  private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {    try {      boolean autoCommit;      try {        autoCommit = connection.getAutoCommit();      } catch (SQLException e) {        // Failover to true, as most poor drivers        // or databases won't support transactions        autoCommit = true;      }            final Environment environment = configuration.getEnvironment();      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      final Transaction tx = transactionFactory.newTransaction(connection);      final Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);    } finally {      ErrorContext.instance().reset();    }  }






原创粉丝点击