zoukankan      html  css  js  c++  java
  • mybatis源码解析10---StatementHandler解析

    StatementHandler解析

    接口的作用是statement处理器,位于mybatis包的org.apache.ibatis.executor.statement目录下,源码如下:

     1 package org.apache.ibatis.executor.statement;
     2 
     3 import java.sql.Connection;
     4 import java.sql.SQLException;
     5 import java.sql.Statement;
     6 import java.util.List;
     7 
     8 import org.apache.ibatis.executor.parameter.ParameterHandler;
     9 import org.apache.ibatis.mapping.BoundSql;
    10 import org.apache.ibatis.session.ResultHandler;
    11 
    12 public interface StatementHandler {
    13   
    14   //sql预编译,构建Statement对象
    15   Statement prepare(Connection connection)
    16       throws SQLException;
    17   
    18   //对prepare方法构建的预编译的SQL进行参数的设置
    19   void parameterize(Statement statement)
    20       throws SQLException;
    21    
    22   //批量处理
    23   void batch(Statement statement)
    24       throws SQLException;
    25 
    26   //执行预编译后的SQL--update语句
    27   int update(Statement statement)
    28       throws SQLException;
    29    
    30   //执行预编译后的SQL--select语句
    31   <E> List<E> query(Statement statement, ResultHandler resultHandler)
    32       throws SQLException;
    33   
    34   //获取SQL封装类BoundSql对象
    35   BoundSql getBoundSql();
    36   
    37   //获取参数处理器对象
    38   ParameterHandler getParameterHandler();
    39 
    40 }

    可见StatementHandler的作用就是先通过prepare方法构建一个Statement对象,然后再调用其他方法对Statement对象进行处理

    StatementHandler和Executor类似,StatementHandler也有两个实现类,BaseStatementHandler和RoutingStatementHandler

    而BaseStatement又有三个子类实现它的抽象方法,下面再挨个分析,先看最简单的BaseStatementHandler

    BaseStatementHandler解析

    BaseStatementHandler是一个抽象父类,有三个子类继承于它,源码如下:

      1 package org.apache.ibatis.executor.statement;
      2 
      3 import java.sql.Connection;
      4 import java.sql.SQLException;
      5 import java.sql.Statement;
      6 
      7 import org.apache.ibatis.executor.ErrorContext;
      8 import org.apache.ibatis.executor.Executor;
      9 import org.apache.ibatis.executor.ExecutorException;
     10 import org.apache.ibatis.executor.keygen.KeyGenerator;
     11 import org.apache.ibatis.executor.parameter.ParameterHandler;
     12 import org.apache.ibatis.executor.resultset.ResultSetHandler;
     13 import org.apache.ibatis.mapping.BoundSql;
     14 import org.apache.ibatis.mapping.MappedStatement;
     15 import org.apache.ibatis.reflection.factory.ObjectFactory;
     16 import org.apache.ibatis.session.Configuration;
     17 import org.apache.ibatis.session.ResultHandler;
     18 import org.apache.ibatis.session.RowBounds;
     19 import org.apache.ibatis.type.TypeHandlerRegistry;
     20 
     21 public abstract class BaseStatementHandler implements StatementHandler {
     22 
     23   protected final Configuration configuration;//全局配置
     24   protected final ObjectFactory objectFactory;//对象工厂
     25   protected final TypeHandlerRegistry typeHandlerRegistry;
     26   protected final ResultSetHandler resultSetHandler;//结果集处理器
     27   protected final ParameterHandler parameterHandler;//参数处理器
     28 
     29   protected final Executor executor;//执行器
     30   protected final MappedStatement mappedStatement;//mapper的SQL对象
     31   protected final RowBounds rowBounds;//分页参数
     32 
     33   protected BoundSql boundSql;//sql封装对象
     34 
     35   //构造方法
     36   protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
     37     this.configuration = mappedStatement.getConfiguration();
     38     this.executor = executor;
     39     this.mappedStatement = mappedStatement;
     40     this.rowBounds = rowBounds;
     41 
     42     this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
     43     this.objectFactory = configuration.getObjectFactory();
     44 
     45     if (boundSql == null) { // issue #435, get the key before calculating the statement
     46       generateKeys(parameterObject);
     47       boundSql = mappedStatement.getBoundSql(parameterObject);
     48     }
     49 
     50     this.boundSql = boundSql;
     51 
     52     this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
     53     this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
     54   }
     55 
     56   //返回boundSql
     57   public BoundSql getBoundSql() {
     58     return boundSql;
     59   }
     60 
     61   //返回parameterHandler
     62   public ParameterHandler getParameterHandler() {
     63     return parameterHandler;
     64   }
     65 
     66   //预编译SQL语句
     67   public Statement prepare(Connection connection) throws SQLException {
     68     ErrorContext.instance().sql(boundSql.getSql());
     69     Statement statement = null;
     70     try {
     71       statement = instantiateStatement(connection);//调用抽象方法构建statement对象是,但是没有具体实现,而是交给其子类去实现
     72       setStatementTimeout(statement);//设置statement超时时间
     73       setFetchSize(statement);//设置statement的fetchSize
     74       return statement;
     75     } catch (SQLException e) {
     76       closeStatement(statement);
     77       throw e;
     78     } catch (Exception e) {
     79       closeStatement(statement);
     80       throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
     81     }
     82   }
     83 
     84   protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
     85 
     86   //给statement对象设置timeout
     87   protected void setStatementTimeout(Statement stmt) throws SQLException {
     88     Integer timeout = mappedStatement.getTimeout();
     89     Integer defaultTimeout = configuration.getDefaultStatementTimeout();
     90     if (timeout != null) {
     91       stmt.setQueryTimeout(timeout);
     92     } else if (defaultTimeout != null) {
     93       stmt.setQueryTimeout(defaultTimeout);
     94     }
     95   }
     96 
     97   //给statement对象设置fetchSize
     98   protected void setFetchSize(Statement stmt) throws SQLException {
     99     Integer fetchSize = mappedStatement.getFetchSize();
    100     if (fetchSize != null) {
    101       stmt.setFetchSize(fetchSize);
    102     }
    103   }
    104 
    105   //关闭statement
    106   protected void closeStatement(Statement statement) {
    107     try {
    108       if (statement != null) {
    109         statement.close();
    110       }
    111     } catch (SQLException e) {
    112       //ignore
    113     }
    114   }
    115 
    116    //根据参数对象生成key
    117   protected void generateKeys(Object parameter) {
    118     KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    119     ErrorContext.instance().store();
    120     keyGenerator.processBefore(executor, mappedStatement, null, parameter);
    121     ErrorContext.instance().recall();
    122   }
    123 
    124 }

    可以看出BaseStatementHandler只是实现了StatementHandler的三个方法,其中getBoundSql和getParameterHandler方法只是返回了由构造方法初始化的boundSql和parameterHandler属性,

    而prepare方法是用于构建Statement对象的,但是BaseStatementHandler只是调用了自身的抽象方法instantiateStatement来创建,然后对statement对象进行其他处理,但是创建的过程则没有实现,而是交给了其子类去实现。

    BaseStatementHandler有三个子类,分别为:
    SimpleStatememtHandler:最简单的StatementHandler,处理不带参数运行的SQL
    PreparedStatementHandler:预处理Statement的handler,处理带参数允许的SQL
    CallableStatementHandler:存储过程的Statement的handler,处理存储过程SQL

    先来看最简单的SimpleStatementHandler,它继承于BaseStatementHandler,所以它需要实现StatementHandler的接口,还需要重写父类BaseStatementHandler的抽象方法,源码如下:

     1 package org.apache.ibatis.executor.statement;
     2 
     3 import java.sql.Connection;
     4 import java.sql.ResultSet;
     5 import java.sql.SQLException;
     6 import java.sql.Statement;
     7 import java.util.List;
     8 
     9 import org.apache.ibatis.executor.Executor;
    10 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
    11 import org.apache.ibatis.executor.keygen.KeyGenerator;
    12 import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
    13 import org.apache.ibatis.mapping.BoundSql;
    14 import org.apache.ibatis.mapping.MappedStatement;
    15 import org.apache.ibatis.session.ResultHandler;
    16 import org.apache.ibatis.session.RowBounds;
    17 
    18 public class SimpleStatementHandler extends BaseStatementHandler {
    19 
    20   //构造方法执行父类的构造方法
    21   public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    22     super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    23   }
    24   
    25   //执行update操作
    26   public int update(Statement statement)
    27       throws SQLException {
    28     String sql = boundSql.getSql();
    29     Object parameterObject = boundSql.getParameterObject();
    30     KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    31     int rows;
    32     //最终都是执行statement的getUpdateCount方法
    33     if (keyGenerator instanceof Jdbc3KeyGenerator) {
    34       statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
    35       rows = statement.getUpdateCount();
    36       keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    37     } else if (keyGenerator instanceof SelectKeyGenerator) {
    38       statement.execute(sql);
    39       rows = statement.getUpdateCount();
    40       keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    41     } else {
    42       statement.execute(sql);
    43       rows = statement.getUpdateCount();
    44     }
    45     return rows;
    46   }
    47   
    48   //给statement添加批量处理sql语句
    49   public void batch(Statement statement)
    50       throws SQLException {
    51     String sql = boundSql.getSql();
    52     statement.addBatch(sql);
    53   }
    54 
    55   //执行查询语句
    56   public <E> List<E> query(Statement statement, ResultHandler resultHandler)
    57       throws SQLException {
    58     String sql = boundSql.getSql();
    59     statement.execute(sql);//statement.execute方法执行sql语句
    60     return resultSetHandler.<E>handleResultSets(statement);
    61   }
    62 
    63   //构造Statement对象
    64   protected Statement instantiateStatement(Connection connection) throws SQLException {
    65      //通过Connection来create一个Statement对象
    66     if (mappedStatement.getResultSetType() != null) {
    67       return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    68     } else {
    69       return connection.createStatement();
    70     }
    71   }
    72 
    73   //由于SimpleStatementHandler是处理没有参数的SQL,所以参数设置的方法无需任何处理
    74   public void parameterize(Statement statement) throws SQLException {
    75     // N/A
    76   }
    77 
    78 }

    可以看出主要是通过Connection创建一个Statement对象,然后通过调用Statement的execute方法执行sql语句

    再看下PreparedStatementHandler,源码如下

     1 package org.apache.ibatis.executor.statement;
     2 
     3 import java.sql.Connection;
     4 import java.sql.PreparedStatement;
     5 import java.sql.ResultSet;
     6 import java.sql.SQLException;
     7 import java.sql.Statement;
     8 import java.util.List;
     9 
    10 import org.apache.ibatis.executor.Executor;
    11 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
    12 import org.apache.ibatis.executor.keygen.KeyGenerator;
    13 import org.apache.ibatis.mapping.BoundSql;
    14 import org.apache.ibatis.mapping.MappedStatement;
    15 import org.apache.ibatis.session.ResultHandler;
    16 import org.apache.ibatis.session.RowBounds;
    17 
    18 public class PreparedStatementHandler extends BaseStatementHandler {
    19 
    20   //执行父类构造方法
    21   public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    22     super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    23   }
    24 
    25   //执行update操作
    26   public int update(Statement statement) throws SQLException {
    27     PreparedStatement ps = (PreparedStatement) statement;
    28     ps.execute();
    29     int rows = ps.getUpdateCount();
    30     Object parameterObject = boundSql.getParameterObject();
    31     KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    32     keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    33     return rows;
    34   }
    35 
    36   //给preparedStatement对象添加批量处理sql语句
    37   public void batch(Statement statement) throws SQLException {
    38     PreparedStatement ps = (PreparedStatement) statement;
    39     ps.addBatch();
    40   }
    41 
    42   //执行preparedStatement的查询语句
    43   public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    44     PreparedStatement ps = (PreparedStatement) statement;
    45     ps.execute();
    46     return resultSetHandler.<E> handleResultSets(ps);
    47   }
    48 
    49   //构建Statement的子类PreparedStatement对象
    50   protected Statement instantiateStatement(Connection connection) throws SQLException {
    51     String sql = boundSql.getSql();
    52     if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
    53       String[] keyColumnNames = mappedStatement.getKeyColumns();
    54       if (keyColumnNames == null) {
    55         return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
    56       } else {
    57         return connection.prepareStatement(sql, keyColumnNames);
    58       }
    59     } else if (mappedStatement.getResultSetType() != null) {
    60       return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    61     } else {
    62       return connection.prepareStatement(sql);
    63     }
    64   }
    65 
    66   //给Statement对象设置参数
    67   public void parameterize(Statement statement) throws SQLException {
    68     parameterHandler.setParameters((PreparedStatement) statement);
    69   }
    70 
    71 }

    再看下RoutingStatementHandler,这个相当于一个StatementHandler的路由器,本身不实现任何功能,只是根据传入的参数来选择调用哪个类型的StatementHandler来处理,代码如下:

     1 public class RoutingStatementHandler implements StatementHandler {
     2 
     3 private final StatementHandler delegate;
     4 
     5 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
     6 
     7 switch (ms.getStatementType()) {
     8 case STATEMENT:
     9 delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    10 break;
    11 case PREPARED:
    12 delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    13 break;
    14 case CALLABLE:
    15 delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    16 break;
    17 default:
    18 throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    19 }
    20 
    21 }
    22 
    23 @Override
    24 public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    25 return delegate.prepare(connection, transactionTimeout);
    26 }
    27 
    28 @Override
    29 public void parameterize(Statement statement) throws SQLException {
    30 delegate.parameterize(statement);
    31 }
    32 
    33 @Override
    34 public void batch(Statement statement) throws SQLException {
    35 delegate.batch(statement);
    36 }
    37 
    38 @Override
    39 public int update(Statement statement) throws SQLException {
    40 return delegate.update(statement);
    41 }
    42 
    43 @Override
    44 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    45 return delegate.<E>query(statement, resultHandler);
    46 }
    47 
    48 @Override
    49 public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    50 return delegate.queryCursor(statement);
    51 }
    52 
    53 @Override
    54 public BoundSql getBoundSql() {
    55 return delegate.getBoundSql();
    56 }
    57 
    58 @Override
    59 public ParameterHandler getParameterHandler() {
    60 return delegate.getParameterHandler();
    61 }
    62 }

    可见RoutingStatementHandler的作用就是在构造的时候根据Statement类型来创建不同的处理器,然后调用对应的处理器来进行操作。而在StatementHandler在初始化的时候,都是通过RoutingStatementHandler来进行路由的,Configuration中的创建StatementHandler代码如下:

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

    再看看SimpleStatementHandler是如何执行sql语句的:

    1 @Override
    2 protected Statement instantiateStatement(Connection connection) throws SQLException {
    3 if (mappedStatement.getResultSetType() != null) {
    4 return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    5 } else {
    6 return connection.createStatement();
    7 }
    8 }

    先通过Collection创建Statement对象

    1 @Override
    2 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    3 String sql = boundSql.getSql();
    4 statement.execute(sql);
    5 return resultSetHandler.<E>handleResultSets(statement);
    6 }

    然后通过Statement对象执行sql语句,最后通过ResultSetHandler对象来处理执行后的结果。

  • 相关阅读:
    采用[ICONIX] 方法实践BLOG设计之一 [问题域建模]
    关于“三国众谋士”之IT从业可行性报告
    采用[ICONIX] 方法实践BLOG设计之二 [用例建模]
    NET框架中的 Decorator 和 Strategy 模式
    域模型向左走(充血),向右走(贫血)
    采用[ICONIX] 方法实践BLOG设计之五 [初步设计复核]
    Discuz!NT 缓存设计简析 [原创]
    Discuz!NT控件剖析 之 Tab 属性页 [原创: 附源码]
    没有银弹,但可以"扯蛋"
    Discuz!NT控件剖析 之 Button [原创: 附源码]
  • 原文地址:https://www.cnblogs.com/jackion5/p/9517882.html
Copyright © 2011-2022 走看看