SqlSession

作者: 93张先生 | 来源:发表于2020-09-08 09:22 被阅读0次

    SqlSession

    SqlSession 是 mybatis 主要执行 sql 命令的接口,控制事务、回滚、缓存清除、关闭连接、获取 Connection、获取mappers。

    public interface SqlSession extends Closeable {
    
      /**
       * 泛型方法,参数表示使用的查询 SQL 语句,返回值为查询的结果对象
       * Retrieve a single row mapped from the statement key.
       * @param <T> the returned object type
       * @param statement
       * @return Mapped object
       */
      <T> T selectOne(String statement);
    
      /**
       * Retrieve a single row mapped from the statement key and parameter.
       * @param <T> the returned object type
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement. 用户实参, SQL 语句绑定的实参
       * @return Mapped object
       */
      <T> T selectOne(String statement, Object parameter);
    
      /**
       * Retrieve a list of mapped objects from the statement key and parameter.
       * @param <E> the returned list element type
       * @param statement Unique identifier matching the statement to use.
       * @return List of mapped object
       */
      <E> List<E> selectList(String statement);
    
      /**
       * Retrieve a list of mapped objects from the statement key and parameter.
       * @param <E> the returned list element type
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @return List of mapped object
       */
      <E> List<E> selectList(String statement, Object parameter);
    
      /**
       * Retrieve a list of mapped objects from the statement key and parameter,
       * within the specified row bounds.
       * @param <E> the returned list element type
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @param rowBounds  Bounds to limit object retrieval 用于显示解析结果的范围,limit 0,100
       * @return List of mapped object
       */
      <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
    
      /**
       * selectMap() 方法的原理和参数都与 selectList() 方法类似,但结果集会被映射成 Map 对象返回。其中第二个参数指定了结采集哪一列作为 Map 的 key
       * The selectMap is a special case in that it is designed to convert a list
       * of results into a Map based on one of the properties in the resulting
       * objects.
       * Eg. Return a of Map[Integer,Author] for selectMap("selectAuthors","id")
       * @param <K> the returned Map keys type
       * @param <V> the returned Map values type
       * @param statement Unique identifier matching the statement to use.
       * @param mapKey The property to use as key for each value in the list. list 转 map;对象字段用来作为map的key,对象做为value; Id : 1,author.id = 1,author.name = job
       * @return Map containing key pair data.
       */
      <K, V> Map<K, V> selectMap(String statement, String mapKey);
    
      /**
       * The selectMap is a special case in that it is designed to convert a list
       * of results into a Map based on one of the properties in the resulting
       * objects.
       * @param <K> the returned Map keys type
       * @param <V> the returned Map values type
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @param mapKey The property to use as key for each value in the list.
       * @return Map containing key pair data.
       */
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
    
      /**
       * The selectMap is a special case in that it is designed to convert a list
       * of results into a Map based on one of the properties in the resulting
       * objects.
       * @param <K> the returned Map keys type
       * @param <V> the returned Map values type
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @param mapKey The property to use as key for each value in the list.
       * @param rowBounds  Bounds to limit object retrieval
       * @return Map containing key pair data.
       */
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
    
      /**
       * 游标查询
       * A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
       * @param <T> the returned cursor element type.
       * @param statement Unique identifier matching the statement to use.
       * @return Cursor of mapped objects
       */
      <T> Cursor<T> selectCursor(String statement);
    
      /**
       * A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
       * @param <T> the returned cursor element type.
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @return Cursor of mapped objects
       */
      <T> Cursor<T> selectCursor(String statement, Object parameter);
    
      /**
       * A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
       * @param <T> the returned cursor element type.
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @param rowBounds  Bounds to limit object retrieval
       * @return Cursor of mapped objects
       */
      <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
    
      /**
       * ResultHandler 查询的结采对象将由此处指定的 ResultHandler 对象处理
       * Retrieve a single row mapped from the statement key and parameter
       * using a {@code ResultHandler}.
       * @param statement Unique identifier matching the statement to use.
       * @param parameter A parameter object to pass to the statement.
       * @param handler ResultHandler that will handle each retrieved row
       */
      void select(String statement, Object parameter, ResultHandler handler);
    
      /**
       * Retrieve a single row mapped from the statement
       * using a {@code ResultHandler}.
       * @param statement Unique identifier matching the statement to use.
       * @param handler ResultHandler that will handle each retrieved row
       */
      void select(String statement, ResultHandler handler);
    
      /**
       * Retrieve a single row mapped from the statement key and parameter
       * using a {@code ResultHandler} and {@code RowBounds}.
       * @param statement Unique identifier matching the statement to use.
       * @param rowBounds RowBound instance to limit the query results
       * @param handler ResultHandler that will handle each retrieved row
       */
      void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
    
      /**
       * Execute an insert statement.
       * @param statement Unique identifier matching the statement to execute.
       * @return int The number of rows affected by the insert.
       */
      int insert(String statement);
    
      /**
       * Execute an insert statement with the given parameter object. Any generated
       * autoincrement values or selectKey entries will modify the given parameter
       * object properties. Only the number of rows affected will be returned.
       * @param statement Unique identifier matching the statement to execute.
       * @param parameter A parameter object to pass to the statement.
       * @return int The number of rows affected by the insert.
       */
      int insert(String statement, Object parameter);
    
      /**
       * Execute an update statement. The number of rows affected will be returned.
       * @param statement Unique identifier matching the statement to execute.
       * @return int The number of rows affected by the update.
       */
      int update(String statement);
    
      /**
       * Execute an update statement. The number of rows affected will be returned.
       * @param statement Unique identifier matching the statement to execute.
       * @param parameter A parameter object to pass to the statement.
       * @return int The number of rows affected by the update.
       */
      int update(String statement, Object parameter);
    
      /**
       * Execute a delete statement. The number of rows affected will be returned.
       * @param statement Unique identifier matching the statement to execute.
       * @return int The number of rows affected by the delete.
       */
      int delete(String statement);
    
      /**
       * Execute a delete statement. The number of rows affected will be returned.
       * @param statement Unique identifier matching the statement to execute.
       * @param parameter A parameter object to pass to the statement.
       * @return int The number of rows affected by the delete.
       */
      int delete(String statement, Object parameter);
    
      /**
       * 提交事务
       * Flushes batch statements and commits database connection.
       * Note that database connection will not be committed if no updates/deletes/inserts were called.
       * To force the commit call {@link SqlSession#commit(boolean)}
       * 除非遇到 updates deletes inserts 否则,transaction不会提交
       */
      void commit();
    
      /**
       * Flushes batch statements and commits database connection.
       * @param force forces connection commit
       * true 强力提交transaction
       */
      void commit(boolean force);
    
      /**
       * Discards pending batch statements and rolls database connection back.
       * Note that database connection will not be rolled back if no updates/deletes/inserts were called.
       * To force the rollback call {@link SqlSession#rollback(boolean)}
       */
      void rollback();
    
      /**
       * Discards pending batch statements and rolls database connection back.
       * Note that database connection will not be rolled back if no updates/deletes/inserts were called.
       * @param force forces connection rollback
       */
      void rollback(boolean force);
    
      /**
       * Flushes batch statements.
       * @return BatchResult list of updated records
       * @since 3.0.6
       */
      List<BatchResult> flushStatements();
    
      /**
       * 关闭当前 Session
       * Closes the session.
       */
      @Override
      void close();
    
      /**
       * Clears local session cache.
       */
      void clearCache();
    
      /**
       * Retrieves current configuration.
       * @return Configuration
       */
      Configuration getConfiguration();
    
      /**
       * 获取 type 对应的 mapper
       * Retrieves a mapper.
       * @param <T> the mapper type
       * @param type Mapper interface class
       * @return a mapper bound to this SqlSession
       */
      <T> T getMapper(Class<T> type);
    
      /**
       * Retrieves inner database connection.
       * @return Connection
       */
      Connection getConnection();
    }
    
    

    UML 类图

    image.png

    DefaultSqlSession

    在 DefaultSqlSession 中使用到了策略模式, DefaultSqlSession 扮演了 Context 的角色,而将所有数据库相关的操作全部封装到 Executor 接口实现中,并通过 executor 字段选择不同的 Executor 实现。

    • Executor 相当于策略接口
    • SimpleExecutor、ReuseExecutor、BatchExecutor、CachingExecutor 相当于具体的策略实现

    根据不同的 ExecutorType,选择不同的策略。

    public enum ExecutorType {
      SIMPLE, REUSE, BATCH
    }
    
    public class DefaultSqlSession implements SqlSession {
      // 全局配置对象
      private final Configuration configuration;
      // 底层依赖的 Executor
      private final Executor executor;
      // 是否自动提交事务
      private final boolean autoCommit;
      // 当前缓存中是否有脏数据
      private boolean dirty;
      // 为防止用户忘记关闭已打开的游标对象,会通过 cursorList 字段记录由该 SqlSession 对象生成的游标对象,在 DefaultSqlSession.close() 方法中会统一关闭这些游标对象
      private List<Cursor<?>> cursorList;
    
      public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
      }
    
      public DefaultSqlSession(Configuration configuration, Executor executor) {
        this(configuration, executor, false);
      }
    
      @Override
      public <T> T selectOne(String statement) {
        return this.selectOne(statement, null);
      }
    
      @Override
      public <T> T selectOne(String statement, Object parameter) {
        // Popular vote was to return null on 0 results and throw exception on too many.
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) {
          return list.get(0);
        } else if (list.size() > 1) {
          throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
          return null;
        }
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
        return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
        return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
        final List<? extends V> list = selectList(statement, parameter, rowBounds);
        final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
                configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
        final DefaultResultContext<V> context = new DefaultResultContext<>();
        for (V o : list) {
          context.nextResultObject(o);
          mapResultHandler.handleResult(context);
        }
        return mapResultHandler.getMappedResults();
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement) {
        return selectCursor(statement, null);
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement, Object parameter) {
        return selectCursor(statement, parameter, RowBounds.DEFAULT);
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
        try {
          MappedStatement ms = configuration.getMappedStatement(statement);
          Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
          registerCursor(cursor);
          return cursor;
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      @Override
      public <E> List<E> selectList(String statement) {
        return this.selectList(statement, null);
      }
    
      @Override
      public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
      }
    
      @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();
        }
      }
    
      @Override
      public void select(String statement, Object parameter, ResultHandler handler) {
        select(statement, parameter, RowBounds.DEFAULT, handler);
      }
    
      @Override
      public void select(String statement, ResultHandler handler) {
        select(statement, null, RowBounds.DEFAULT, handler);
      }
    
      @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 {
          // TODO: 19-12-18 use case;play a role
          ErrorContext.instance().reset();
        }
      }
    
      @Override
      public int insert(String statement) {
        return insert(statement, null);
      }
    
      @Override
      public int insert(String statement, Object parameter) {
        //调用了update语句
        return update(statement, parameter);
      }
    
      @Override
      public int update(String statement) {
        return update(statement, null);
      }
    
      @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 int delete(String statement) {
        return update(statement, null);
      }
    
      @Override
      public int delete(String statement, Object parameter) {
        return update(statement, parameter);
      }
    
      @Override
      public void commit() {
        commit(false);
      }
    
      @Override
      public void commit(boolean force) {
        try {
          executor.commit(isCommitOrRollbackRequired(force));
          dirty = false;
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      @Override
      public void rollback() {
        rollback(false);
      }
    
      @Override
      public void rollback(boolean force) {
        try {
          executor.rollback(isCommitOrRollbackRequired(force));
          dirty = false;
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      @Override
      public List<BatchResult> flushStatements() {
        try {
          return executor.flushStatements();
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error flushing statements.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      @Override
      public void close() {
        try {
          executor.close(isCommitOrRollbackRequired(false));
          closeCursors();
          dirty = false;
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      private void closeCursors() {
        if (cursorList != null && !cursorList.isEmpty()) {
          for (Cursor<?> cursor : cursorList) {
            try {
              cursor.close();
            } catch (IOException e) {
              throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
            }
          }
          cursorList.clear();
        }
      }
    
      @Override
      public Configuration getConfiguration() {
        return configuration;
      }
    
      @Override
      public <T> T getMapper(Class<T> type) {
        return configuration.getMapper(type, this);
      }
    
      @Override
      public Connection getConnection() {
        try {
          return executor.getTransaction().getConnection();
        } catch (SQLException e) {
          throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
        }
      }
    
      @Override
      public void clearCache() {
        executor.clearLocalCache();
      }
    
      private <T> void registerCursor(Cursor<T> cursor) {
        if (cursorList == null) {
          cursorList = new ArrayList<>();
        }
        cursorList.add(cursor);
      }
    
      /**
       * dirty 与 autoCommit 以及 用户传入的 force 参数共同决定是否提交或回滚事务
       * @param force
       * @return
       */
      private boolean isCommitOrRollbackRequired(boolean force) {
        return (!autoCommit && dirty) || force;
      }
    
      /**
       * 查询参数包装
       * @param object
       * @return
       */
      private Object wrapCollection(final Object object) {
        if (object instanceof Collection) {
          StrictMap<Object> map = new StrictMap<>();
          map.put("collection", object);
          if (object instanceof List) {
            map.put("list", object);
          }
          return map;
        } else if (object != null && object.getClass().isArray()) {
          StrictMap<Object> map = new StrictMap<>();
          map.put("array", object);
          return map;
        }
        return object;
      }
    
      public static class StrictMap<V> extends HashMap<String, V> {
    
        private static final long serialVersionUID = -5741767162221585340L;
    
        @Override
        public V get(Object key) {
          if (!super.containsKey(key)) {
            throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
          }
          return super.get(key);
        }
    
      }
    
    }
    

    SqlSessionFactory

    SqlSessionFactory 负责创建 SqlSession 对象,其中只包含了多个 openSession() 方法的重载,可以通过其参数指定事务的隔离级别、底层使用 Executor 的类型以及是否自动提交事务等方面的配置。

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

    DefaultSqlSessionFactory

    DefaultSqlSessionFactory 是一个具体工厂类,实现了 SqlSessionFactory 接口。DefaultSqlSessionFactory 主要提供了两种创建 DefaultSqlSession 对象的方式,一种是通过数据源获取数据库连接,并创建 Executor 对象以及 DefaultSqlSession 对象。另一种方式是用户提供数据库连接对象, DefaultSqlSessionFactory 会使用该据库连接对象创建 Executor 对象 DefaultSqlSession 对象。

    public class DefaultSqlSessionFactory implements SqlSessionFactory {
    
      private final Configuration configuration;
    
      public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
      }
    
      @Override
      public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
      }
    
      @Override
      public SqlSession openSession(boolean autoCommit) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType) {
        return openSessionFromDataSource(execType, null, false);
      }
    
      @Override
      public SqlSession openSession(TransactionIsolationLevel level) {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return openSessionFromDataSource(execType, level, false);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
        return openSessionFromDataSource(execType, null, autoCommit);
      }
    
      @Override
      public SqlSession openSession(Connection connection) {
        return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, Connection connection) {
        return openSessionFromConnection(execType, connection);
      }
    
      @Override
      public Configuration getConfiguration() {
        return configuration;
      }
    
      private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
          // 获取 mybatis-config.xml 配置文件中配置的 Environment 对象
          final Environment environment = configuration.getEnvironment();
          // 获取 TransactionFactory
          final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
          // 创建 Transaction 对象
          tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
          // 创建 Executor 对象
          final Executor executor = configuration.newExecutor(tx, execType);
          // 创建 DefaultSqlSession 对象
          return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
          // 关闭 Transaction
          closeTransaction(tx); // may have fetched a connection so lets call close()
          throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
        } finally {
          ErrorContext.instance().reset();
        }
      }
    
      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();
        }
      }
    
      /**
       * 获取 TransactionFactory 对象
       * @param environment
       * @return
       */
      private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
        if (environment == null || environment.getTransactionFactory() == null) {
          return new ManagedTransactionFactory();
        }
        return environment.getTransactionFactory();
      }
    
      /**
       * 关闭 Transaction
       * @param tx
       */
      private void closeTransaction(Transaction tx) {
        if (tx != null) {
          try {
            tx.close();
          } catch (SQLException ignore) {
            // Intentionally ignore. Prefer previous error. 故意忽略喜欢先前的错误;
          }
        }
      }
    
    }
    
    

    SqlSessionManager

    • SqlSessionManager 实现了SqlSessionFactorySqlSession 接口,重写了这两个接口的所有方法;
    • 包含两个成员变量 sqlSessionFactorysqlSessionProxy,通过newInstance()方法调用构造方法进行赋值;
    • sqlSessionProxy 为一个代理对象,通过 Java 反射技术生成代理对象。
    • SqlSeesion 接口定义了 close()commit()rollback()clearCache() 等方法,为了操作同一个SqlSeesion对象,引入了 ThreadLocal 变量,通过localSqlSession确保操作同一个SqlSession,保证了线程安全。

    SqlSessionManager 与 DefaultSqlSessionFactory 的主要不同点是 SqlSessionManager 提供了两种模式:第一种模式与 DefaultSqlSessionFactory 的行为相同,同一线程每次通过SqlSessionManager 对象访问数据库时,都会创建新的 DefaultSession 对象完成数据库操作;第二种模式 SqlSessionManager 通过 localSqlSession 这个 ThreadLocal 变量,记录与当前线程绑定的 SqlSession 对象,使当前前线程循环使用,从而避免在同一线程多次创建 SqlSession 对象带来的性能损失。

    public class SqlSessionManager implements SqlSessionFactory, SqlSession {
    
      private final SqlSessionFactory sqlSessionFactory;
      // localSqlSession 中记录的 SqlSession 对象的代理,在 SqlSessionManager 初始化时,会使用 JDK 动态代理的方式为 localSqlSession 创建代理对象
      private final SqlSession sqlSessionProxy;
      // ThreadLocal 变量,记录一个与当前线程绑定的Sql SqlSession 对象
      private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
    
      private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
        // 使用动态代理的方式创建 SqlSession 的代理对象
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[]{SqlSession.class},
            new SqlSessionInterceptor());
      }
      // 通过 newInstance() 方法创建 SqlSessionManager 对象
      public static SqlSessionManager newInstance(Reader reader) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
      }
    
      public static SqlSessionManager newInstance(Reader reader, String environment) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
      }
    
      public static SqlSessionManager newInstance(Reader reader, Properties properties) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
      }
    
      public static SqlSessionManager newInstance(InputStream inputStream) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
      }
    
      public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
      }
    
      public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
        return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
      }
    
      public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionManager(sqlSessionFactory);
      }
      //通过此方法,对localSqlSession赋值;
      //其他框架和 mybatis 进行对接的时候,不会使用 SqlSessionManager 类,所以这个 localSqlSession 的线程缓存也没有被使用
      public void startManagedSession() {
        this.localSqlSession.set(openSession());
      }
    
      public void startManagedSession(boolean autoCommit) {
        this.localSqlSession.set(openSession(autoCommit));
      }
    
      public void startManagedSession(Connection connection) {
        this.localSqlSession.set(openSession(connection));
      }
    
      public void startManagedSession(TransactionIsolationLevel level) {
        this.localSqlSession.set(openSession(level));
      }
    
      public void startManagedSession(ExecutorType execType) {
        this.localSqlSession.set(openSession(execType));
      }
    
      public void startManagedSession(ExecutorType execType, boolean autoCommit) {
        this.localSqlSession.set(openSession(execType, autoCommit));
      }
    
      public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {
        this.localSqlSession.set(openSession(execType, level));
      }
    
      public void startManagedSession(ExecutorType execType, Connection connection) {
        this.localSqlSession.set(openSession(execType, connection));
      }
    
      public boolean isManagedSessionStarted() {
        return this.localSqlSession.get() != null;
      }
    
      @Override
      public SqlSession openSession() {
        return sqlSessionFactory.openSession();
      }
    
      @Override
      public SqlSession openSession(boolean autoCommit) {
        return sqlSessionFactory.openSession(autoCommit);
      }
    
      @Override
      public SqlSession openSession(Connection connection) {
        return sqlSessionFactory.openSession(connection);
      }
    
      @Override
      public SqlSession openSession(TransactionIsolationLevel level) {
        return sqlSessionFactory.openSession(level);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType) {
        return sqlSessionFactory.openSession(execType);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
        return sqlSessionFactory.openSession(execType, autoCommit);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return sqlSessionFactory.openSession(execType, level);
      }
    
      @Override
      public SqlSession openSession(ExecutorType execType, Connection connection) {
        return sqlSessionFactory.openSession(execType, connection);
      }
    
      @Override
      public Configuration getConfiguration() {
        return sqlSessionFactory.getConfiguration();
      }
    
      @Override
      public <T> T selectOne(String statement) {
        return sqlSessionProxy.selectOne(statement);
      }
    
      @Override
      public <T> T selectOne(String statement, Object parameter) {
        return sqlSessionProxy.selectOne(statement, parameter);
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
        return sqlSessionProxy.selectMap(statement, mapKey);
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
        return sqlSessionProxy.selectMap(statement, parameter, mapKey);
      }
    
      @Override
      public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
        return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement) {
        return sqlSessionProxy.selectCursor(statement);
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement, Object parameter) {
        return sqlSessionProxy.selectCursor(statement, parameter);
      }
    
      @Override
      public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
        return sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
      }
    
      @Override
      public <E> List<E> selectList(String statement) {
        return sqlSessionProxy.selectList(statement);
      }
    
      @Override
      public <E> List<E> selectList(String statement, Object parameter) {
        return sqlSessionProxy.selectList(statement, parameter);
      }
    
      @Override
      public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        return sqlSessionProxy.selectList(statement, parameter, rowBounds);
      }
    
      @Override
      public void select(String statement, ResultHandler handler) {
        sqlSessionProxy.select(statement, handler);
      }
    
      @Override
      public void select(String statement, Object parameter, ResultHandler handler) {
        sqlSessionProxy.select(statement, parameter, handler);
      }
    
      @Override
      public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        sqlSessionProxy.select(statement, parameter, rowBounds, handler);
      }
    
      @Override
      public int insert(String statement) {
        return sqlSessionProxy.insert(statement);
      }
    
      @Override
      public int insert(String statement, Object parameter) {
        return sqlSessionProxy.insert(statement, parameter);
      }
    
      @Override
      public int update(String statement) {
        return sqlSessionProxy.update(statement);
      }
    
      @Override
      public int update(String statement, Object parameter) {
        return sqlSessionProxy.update(statement, parameter);
      }
    
      @Override
      public int delete(String statement) {
        return sqlSessionProxy.delete(statement);
      }
    
      @Override
      public int delete(String statement, Object parameter) {
        return sqlSessionProxy.delete(statement, parameter);
      }
    
      @Override
      public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
      }
    
      @Override
      public Connection getConnection() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot get connection.  No managed session is started.");
        }
        return sqlSession.getConnection();
      }
    
      @Override
      public void clearCache() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot clear the cache.  No managed session is started.");
        }
        sqlSession.clearCache();
      }
    
      @Override
      public void commit() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
        }
        sqlSession.commit();
      }
    
      @Override
      public void commit(boolean force) {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
        }
        sqlSession.commit(force);
      }
    
      @Override
      public void rollback() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
        }
        sqlSession.rollback();
      }
    
      @Override
      public void rollback(boolean force) {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
        }
        sqlSession.rollback(force);
      }
    
      @Override
      public List<BatchResult> flushStatements() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
        }
        return sqlSession.flushStatements();
      }
    
      @Override
      public void close() {
        final SqlSession sqlSession = localSqlSession.get();
        if (sqlSession == null) {
          throw new SqlSessionException("Error:  Cannot close.  No managed session is started.");
        }
        try {
          sqlSession.close();
        } finally {
          localSqlSession.set(null);
        }
      }
    
      /**
       * 通过代理调用相应的方法 select、update、delete
       */
      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 对象,则创建新的的 SqlSession 对象
            try (SqlSession autoSqlSession = openSession()) {
              try {
                // 通过新建的 SqlSession 对象完成数据操作
                final Object result = method.invoke(autoSqlSession, args);
                // 提交事务
                autoSqlSession.commit();
                return result;
              } catch (Throwable t) {
                // 回滚事务
                autoSqlSession.rollback();
                throw ExceptionUtil.unwrapThrowable(t);
              }
            }
          }
        }
      }
    
    }
    
    

    SqlSessionFactoryBuilder

    SqlSessionFactoryBuilder 并没有严谨的使用Builder模式用来创建SqlSessionFactory
    创建 SqlSessionFactory 对象两种方式:

      1. 使用 Configuration 对象(mybaits全局配置对象),创建一个默认的DefaultSqlSessionFactory对象;
      1. 通过配置文件*.xml文件流、environmentproperties 等解析为Configuration对象,然后通过Configuration对象,创建默认的DefaultSqlSessionFactory对象;
    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);
          // 构建 SqlSessionFactory 对象
          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);
      }
    
    }
    

    相关文章

      网友评论

        本文标题:SqlSession

        本文链接:https://www.haomeiwen.com/subject/zlplektx.html