MyBatis的SqlSession理解(一)


SqlSession是Mybatis最重要的構建之一,可以認為Mybatis一系列的配置目的是生成類似JDBC生成的Connection對象的statement對象,這樣才能與數據庫開啟“溝通”,通過SqlSession可以實現增刪改查(當然現在更加推薦是使用Mapper接口形式)

 

1 .sqlsession的創建:

SqlSessionFactoryBuilder創建SqlSessionFactory  openSession,sqlSession 執行增刪改查
用了注解是通過org.mybatis.spring.SqlSessionFactoryBean該類創建sqlsession的,而mapper里面的每一個方法稱為statement。
    public void deleteUserTest() throws IOException {
        // mybatis配置文件
        String resource = "SqlMapConfig.xml";
        // 得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 創建會話工廠,傳入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(inputStream);
        // 通過工廠得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 傳入id刪除 用戶
        sqlSession.delete("test.deleteUser", 39);
//更新
sqlSession.update("test.updateUser", user);
//插入
sqlSession.insert("test.insertUser", user);
//查詢
List<User> list = sqlSession.selectOne("test.findUserByName", "小明");
// 提交事務 增刪改 需要commit,查詢無需commit sqlSession.commit(); // 關閉會話 sqlSession.close(); }

2.SqlSession原理

SqlSession提供select/insert/update/delete方法,在舊版本中使用使用SqlSession接口的這些方法,但是新版的Mybatis中就會建議使用Mapper接口的方法。

映射器其實就是一個動態代理對象,進入到MapperMethod的execute方法就能簡單找到SqlSession的刪除、更新、查詢、選擇方法,從底層實現來說:通過動態代理技術,讓接口跑起來,之后采用命令模式,最后還是采用了SqlSession的接口方法(getMapper()方法等到Mapper)執行SQL查詢(也就是說Mapper接口方法的實現底層還是采用SqlSession接口方法實現的)。

3.SqlSession重要的四個對象

1)Execute:調度執行StatementHandler、ParmmeterHandler、ResultHandler執行相應的SQL語句;

2)StatementHandler:使用數據庫中Statement(PrepareStatement)執行操作,即底層是封裝好了的prepareStatement;

3)ParammeterHandler:處理SQL參數;

4)ResultHandler:結果集ResultSet封裝處理返回。

 

1 Execute執行器

execute接口有以下方法

 

執行器起到至關重要的作用,它是真正執行Java與數據庫交互的東西,參與了整個SQL查詢執行過程中。

1)主要有三種執行器:簡易執行器SIMPLE(不配置就是默認執行器)、REUSE是一種重用預處理語句、BATCH批量更新、批量專用處理器

2)執行器作用:Executor會先調用StatementHandler的prepare()方法預編譯SQL語句,同時設置一些基本的運行參數,然后調用StatementHandler的parameterize()方法(實際上是啟用了ParameterHandler設置參數)設置參數,resultHandler再組裝查詢結果返回調用者完成一次查詢完成預編譯,簡單總結起來就是即先預編譯SQL語句,之后設置參數(跟JDBC的prepareStatement過程類似)最后如果有查詢結果就會組裝返回。

StatementHandler 接口方法
public interface StatementHandler {
  //預編譯SQL語句
  Statement prepare(Connection connection)
      throws SQLException;
  //設置一些基本的運行參數
  void parameterize(Statement statement)
      throws SQLException;

  void batch(Statement statement)
      throws SQLException;

  int update(Statement statement)
      throws SQLException;

  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  BoundSql getBoundSql();

  ParameterHandler getParameterHandler();

}

第一:Executor通過Configuration對象中newExecutor()方法中選擇相應的執行器生成

//Configuration 類
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor, autoCommit); }
//最后在可以在調用真正的Executor前可以修改插件代碼,執行攔截器 executor
= (Executor) interceptorChain.pluginAll(executor); return executor; }
//InterceptorChain 類中pluginAll 方法:    
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

 

 
 

第二:在執行器中StatementHandler是根據Configuration構建的

public class SimpleExecutor extends BaseExecutor {

  public SimpleExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }

  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      //獲取StatementHandler 對象
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//調到最后一個方法查看詳細內容 stmt
= prepareStatement(handler, ms.getStatementLog()); return handler.update(stmt); } finally { closeStatement(stmt); } } public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } } public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException { return Collections.emptyList(); } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection); //設置執行參數 handler.parameterize(stmt); return stmt; } }

第三:Executor會執行StatementHandler的prepare()方法進行預編譯---->填入connection對象等參數---->再調用parameterize()方法設置參數---->完成預編譯

   //SimpleExecutor類  
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    // 執行handler.prepare()預編譯sql
    stmt = handler.prepare(connection);
//設置執行參數 handler.parameterize(stmt);
return stmt; }

2 StatementHanlder數據庫會話器

1)作用:簡單來說就是專門處理數據庫會話。詳細來說就是進行預編譯並且調用ParameterHandler的setParameters()方法設置參數。

2)數據庫會話器主要有三種:SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分別對應Executor的三種執行器(SIMPLE、REUSE、BATCH)

Executor的prepareStatement()方法中調用了StatementHandler的parameterize()

第一:StatementHandler的生成是由Configuration方法中newStatementHandler()方法生成的,但是正在創建的是實現了StatementHandler接口的RoutingStatementHandler對象

//Configuration
public
StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }

第二:RoutingStatementHandler的通過適配器模式找到對應(根據上下文)的StatementHandler執行的,並且有SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分別對應Executor的三種執行器(SIMPLE、REUSE、BATCH)

//RoutingStatementHandler
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }
PreparedStatementHandler , public class PreparedStatementHandler extends BaseStatementHandler  , BaseStatementHandler implements StatementHandler
第三:在BaseStatementHandler中重寫prepare()方法,instantiateStatement()方法完成預編譯,之后設置一些基礎配置(獲取最大行數,超時)
//BaseStatementHandler
 public Statement prepare(Connection connection) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      statement = instantiateStatement(connection);
      setStatementTimeout(statement);
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

第四:instantiateStatement()預編譯實際上也是使用了JDBC的prepareStatement()完成預編譯

  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareStatement(sql);
    }
  }

第五:在prepareStatement中重寫parameterize()方法。prepare()預編譯完成之后,Executor會調用parameterize()方法

 public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
  }

(3)ParameterHandler參數處理器

作用:對預編譯中參數進行設置,如果有配置typeHandler,自然會對注冊的typeHandler對參數進行處理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM