1.SqlSessionFactory

SqlSessionFactory是MyBatis的关键对象。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。同时SqlSessionFactory也是线程安全的,SqlSessionFactory一旦被创建,应该在应用执行期间都存在。在应用运行期间不要重复创建多次,建议使用单例模式。SqlSessionFactory是创建SqlSession的工厂。

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

}

1.1创建SqlSessionFactory

SqlSessionFactory是由SqlSessionFactoryBuilder创建。

SqlSession是线程安全的_SqlSession是线程安全的

2.SqlSession

SqlSession是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection。它是应用程序与持久层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接。可以用SqlSession实例来直接执行被映射的SQL语句。每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,同时SqlSession也是线程不安全的。使用完SqlSeesion之后关闭Session很重要,应该确保使用finally块来关闭它。

2.1创建SqlSession

SqlSession对象是由SqlSessionFactory对象创建。主要代码如下:

// 从数据源获取connection 进而获取SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    // 通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
    final Environment environment = configuration.getEnvironment();
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    // autoCommit 设置从Transaction获取的connection是否可以 自动提交
    // Transaction封装了数据库连接connection的获取、释放、关闭、提交、回滚
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    // 把Transaction封装进Executor里面执行增删改查。
    final Executor executor = configuration.newExecutor(tx, execType);
    // Executor封装进SqlSession。作为门面来执行一系列操作
    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对象之后就可以利用SqlSession内部的方法进行CRUD操作了。

与数据库打交道必不可少的是JDBC Connection。Transaction对象就是封装了数据源与Connection。可以从连接池中获取连接,使用后关闭连接,把连接回归连接池中,实现connection的复用。不用重复新建连接。可以参考PooledDataSource代码

SqlSession是线程安全的_List_02

2.2 sqlSession的功能

  • 主要API:增、删、改、查
  • 辅助API:提交、关闭会话、事务回滚、清除缓存、批量操作时刷新Statements

这些功能都依赖于Executor执行器来实现

SqlSession是线程安全的_SqlSession是线程安全的_03

主要方法如下:

2.2.1 查询

  • 直接返回列表
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
  • 把结果封装进传入的ResultHandler中,会在查询结果集映射的时候使用。
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    executor.query(ms, wrapCollection(parameter), rowBounds, handler);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
public class DefaultResultHandler implements ResultHandler<Object> {

  private final List<Object> list;

  public DefaultResultHandler() {
    list = new ArrayList<>();
  }

  @SuppressWarnings("unchecked")
  public DefaultResultHandler(ObjectFactory objectFactory) {
    list = objectFactory.create(List.class);
  }

  @Override
  public void handleResult(ResultContext<?> context) {
    list.add(context.getResultObject());
  }

  public List<Object> getResultList() {
    return list;
  }

}

2.2.2 更新(增、删、改)

public int update(String statement, Object parameter) {
  try {
    dirty = true;
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.update(ms, wrapCollection(parameter));
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
xception e) {
    throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}