MyBatis  会话

MyBatis 会话

MyBatis 所有的 CURD 操作都是在一个会话中完成的,本文简单介绍一下 MyBatis 会话相关的知识。

如何创建一个会话

在不与 Spring 结合的情况下,我们需要自己手动创建会话,看示例:

    public static void main(String[] args) {
        String resourceLocation = "config/mybatis-config.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(resourceLocation);
            //①解析 xml 配置文件,创建会话工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //②从工厂中获取会话实例
            SqlSession sqlSession = sqlSessionFactory.openSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

创建会话工厂

首先通过 SqlSessionFactoryBuilder#build 方法解析配置文件获取会话工厂实例,正常情况下这个步骤只会在服务启动时执行一次。具体构造逻辑:

  // org.apache.ibatis.session.SqlSessionFactoryBuilder

  //重载方法
  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      //①构建一个XML配置类解析器
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      //②首先解析 XML 配置文件中各节点信息,创建一个全局唯一的 Configuration 实例
      //然后调用重载方法创建一个 DefaultSqlSessionFactory
      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.
      }
    }
  }

其实这一步最关键的地方就是执行 XMLConfigBuilder#parse 方法解析配置文件各个节点信息,创建一个全局唯一Configuration 实例,具体逻辑就不贴了,有点复杂,反正就是把 xml 文件中配置的信息转换为 Java 对象存在 Configuration 实例中。

创建会话实例

获得会话工厂后我们就能很轻松的创建一个会话实例了,调用SqlSessionFactory#openSession 方法即可。常用的 SqlSessionFactory 实现是 DefaultSqlSessionFactory,先贴一下它创建会话的逻辑。

  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

  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();
    }
  }

逻辑很清晰,首先从配置类中获取当前环境信息,然后从环境信息中获取事务工厂,再数据源、事务隔离级别、是否自动提交等参数创建当前事务实例。有了事务实例,再结合执行器类型创建一个执行器实例(执行器作为核心组件之一,后面单独介绍)。最后一步创建会话实例,其持有全局唯一的配置对象和执行器实例,用于后续的 CURD 操作。

有了会话能干什么

SqlSession 提供了 select insert update delete 等操作方法,具备 CURD 的能力。不过这些都是需要指定 statemet 才能运行,不太方便,它还额外提供了 getMapper 方法获取 Mapper 接口的代理对象,这样就能直接调用对应的方法完成操作了。并且它还提供了 commit rollback 方法用来支持事务操作。

    public static void main(String[] args) {
        String resourceLocation = "config/mybatis-config.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(resourceLocation);
            //解析 xml 配置文件,创建会话工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //从工厂中获取会话实例
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //1. 指定 statement 查询
            Object result = sqlSession.selectOne("club.wyc1856.mybatisspringboot.mapper.wyc1856.UserMapper.findById", 1);
            System.out.println(result);

            //2.通过 Mapper 接口代理类查询
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.findById(1);
            System.out.println(user);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

注意

Sqlsession 不是线程安全的,不能作为类的静态变量或者实例变量,最好每次用的时候在方法中调用 Sqlsessionfactory#opensession 获取会话实例,用完关闭。

总结

mybatis-sqlSession