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對象來處理執行后的結果。

 


免責聲明!

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



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