mybatis源码阅读(一):SqlSession和SqlSessionFactory

一、接口定义

    听名字就知道这里使用了工厂方法模式,SqlSessionFactory负责创建SqlSession对象。其中开发人员最常用的就是DefaultSqlSession

(1)SqlSession接口定义

public interface SqlSession extends Closeable {

  // 泛型方法,参数表示使用的查询SQL语句,返回值为查询的结果对象
  <T> T selectOne(String statement);

  // 第二个参数表示需要用户传入的实参,也就是SQL语句绑定的实参
  <T> T selectOne(String statement, Object parameter);

  // 查询结果集有多条记录,会封装成结果对象列表返回
  <E> List<E> selectList(String statement);
  <E> List<E> selectList(String statement, Object parameter);
  // 第三个参数用于限制解析结果集的范围
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

  /**
   *
   *  selectMap 方法的原理和参数都与selectList方法类型,但结果集会被映射成Map对象返回
   *  其中mapKey参数指定了结果集哪一列作为map的key,其他参数同上
   */
  <K, V> Map<K, V> selectMap(String statement, String mapKey);
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

  // 返回值是游标对象,参数同上
  <T> Cursor<T> selectCursor(String statement);
  <T> Cursor<T> selectCursor(String statement, Object parameter);
  <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);

  // 查询的结果对象将由此处指定的handler对象处理,其余参数同上
  void select(String statement, Object parameter, ResultHandler handler);
  void select(String statement, ResultHandler handler);
  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

  // 执行insert语句
  int insert(String statement);
  int insert(String statement, Object parameter);

  // 执行update语句
  int update(String statement);
  int update(String statement, Object parameter);

  // 执行delete
  int delete(String statement);
  int delete(String statement, Object parameter);

  // 提交事务
  void commit();
  void commit(boolean force);

  // 事务回滚
  void rollback();
  void rollback(boolean force);

  // 将请求刷新到数据库
  List<BatchResult> flushStatements();

  // 关闭当前session
  @Override
  void close();

  // 清空session 缓存
  void clearCache();

  // 获取Configuration 对象
  Configuration getConfiguration();

  // 获取type 对象的Mapper对象
  <T> T getMapper(Class<T> type);

  // 获取该Sqlsession 对象的数据库连接
  Connection getConnection();
}

SqlSession数据库的C、R、U、D及事务处理接口,你懂的。

(2)SqlSessionFactory

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

这个大家也都懂的

SqlSession实现类:DefaultSqlSession和SqlSessionManager

SqlSessionFactory实现类:DefaultSqlSessionFactory和SqlSessionManager

(3)DefaultSqlSession

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

这里主要看这两个方法,因为delete和insert最终执行掉用的都是update方法,查询就更不用说了。从代码上看都是从configuration对象中获取MappedStatement 对象 然后把事情交给小弟Executor去执行,这里用了很典型的策略设计模式,这个关于Executor 后面介绍。

(4)DefaultSqlSessionFactory

/**
 * 通过数据源获取数据库连接,并创建Executor以及DefaultSqlSession对象
 */
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();
  }
}

/**
 *  用户提供数据库连接对象,使用该数据库连接对象创建Executor和DefaultSqlSession对象
 */
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();
  }
}

DefaultSqlSessionFactory主要提供了两种创建DefaultSqlSession对象的方式,一种是通过数据源获取数据库连接,并创建Executor以及DefaultSqlSession对象,另一种是用户提供数据库连接对象,使用该数据库连接对象创建Executor和DefaultSqlSession对象。

(5)SqlSessionManager

SqlSessionManager同时实现SqlSession接口和SqlSessionFactory接口,也就是同时提供了创建SqlSession对象以及SqlSession对象操作数据库的功能。SqlSessionManager与DefaultSqlSessionFactory的主要不同点是SqlSessionManager提供了两种模式,一种是和DefaultSqlSessionFactory的行为相同,同一线程每次访问数据库就都会创建新的DefaultSqlSession,第二种是通过ThreadLocal变量记录当前线程的SqlSession对象,避免同一线程多次创建SqlSession对象。至于使用动态代理的目的,是为了通过拦截器InvocationHandler,增强目标target的方法调用。

private final SqlSessionFactory sqlSessionFactory;
// SqlSession的代理对象 会使用JDK的动态代理方式实现
private final SqlSession sqlSessionProxy;

/**
 * ThreadLocal 变量,记录一个与当前线程绑定的SqlSession对象
 * localSqlSession 中记录的SqlSession对象的代理对象,在SqlSessionManager初始化的时候
 */
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
/**
 * SqlSessionManager 的私有构造方法
 */
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
  this.sqlSessionFactory = sqlSessionFactory;
  // 使用动态代理生成SqlSession的代理对象
  this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
      SqlSessionFactory.class.getClassLoader(),
      new Class[]{SqlSession.class},
      new SqlSessionInterceptor());
}
  /**
   * 通过newInstance方法创建SqlSessionManager对象
   * @param reader
   * @return
   */
  public static SqlSessionManager newInstance(Reader reader) {
      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
  }
// 内部类
private class SqlSessionInterceptor implements InvocationHandler {
      public SqlSessionInterceptor() {
          // Prevent Synthetic Access
      }

      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          // 获取当前线程绑定的SqlSession对象
          final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
          if (sqlSession != null) {// 第二种模式
              try {
                  return method.invoke(sqlSession, args);
              } catch (Throwable t) {
                  throw ExceptionUtil.unwrapThrowable(t);
              }
          } else {// 第一种模式 创建新的SqlSession
              final SqlSession autoSqlSession = openSession();
              try {
                  final Object result = method.invoke(autoSqlSession, args);
                  autoSqlSession.commit();
                  return result;
              } catch (Throwable t) {
                  autoSqlSession.rollback();
                  throw ExceptionUtil.unwrapThrowable(t);
              } finally {
                  autoSqlSession.close();
              }
          }
      }
}

猜你喜欢

转载自my.oschina.net/u/3737136/blog/1800634
今日推荐