mybatis源码阅读(六) ---StatementHandler了解一下
轉(zhuǎn)載自??mybatis源碼閱讀(六) ---StatementHandler了解一下
StatementHandler類結(jié)構(gòu)圖與接口設(shè)計(jì)
BaseStatementHandler:一個(gè)抽象類,只是實(shí)現(xiàn)了一些不涉及具體操作的方法
RoutingStatementHandler:類似路由器,根據(jù)配置文件來(lái)路由選擇具體實(shí)現(xiàn)類SimpleStatementHandler、CallableStatementHandler和PreparedStatementHandler
SimpleStatementHandler:就是直接使用普通的Statement對(duì)象,這樣每次執(zhí)行SQL語(yǔ)句都需要數(shù)據(jù)庫(kù)對(duì)SQL進(jìn)行預(yù)編譯
PrepareStatementHandler:使用PrepareStatement執(zhí)行,雖然初次創(chuàng)建PrepareStatement時(shí)開(kāi)銷比較大,但在多次處理SQL時(shí)只需要初始化一次,可以有效提高性能
CallableStatementHandler:使用CallableStatement執(zhí)行,CallableStatement是用來(lái)執(zhí)行存儲(chǔ)過(guò)程的。
在每個(gè)mapper節(jié)點(diǎn)可以設(shè)置statementType決定是否使用誰(shuí) ,如下
<!-- statementType (可選配置,默認(rèn)配置為PREPARED)STATEMENT,PREPARED 或 CALLABLE 的一個(gè)。這會(huì)讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED。 --> <select id="findUserById" resultType="com.lpf.entity.User" statementType="PREPARED">select * from m_user where id = #{id} </select>1. StatementHandler
public interface StatementHandler {// 從連接中獲取一個(gè)Statement對(duì)象Statement prepare(Connection connection, Integer transactionTimeout)throws SQLException;// 綁定Statement執(zhí)行是所需要的參數(shù)void parameterize(Statement statement)throws SQLException;// 批量執(zhí)行SQLvoid batch(Statement statement)throws SQLException;// 執(zhí)行update,delete,insert語(yǔ)句int update(Statement statement)throws SQLException;// 執(zhí)行select語(yǔ)句<E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException;<E> Cursor<E> queryCursor(Statement statement)throws SQLException;BoundSql getBoundSql();// 獲取封裝的ParameterterHandler對(duì)象ParameterHandler getParameterHandler();}2. BaseStatementHandler
BaseStatementHandler是一個(gè)抽象類,和Executor一樣使用了模板設(shè)計(jì)方法。代碼如下:
public abstract class BaseStatementHandler implements StatementHandler {protected final Configuration configuration;protected final ObjectFactory objectFactory;protected final TypeHandlerRegistry typeHandlerRegistry;//將結(jié)果映射成結(jié)果對(duì)象protected final ResultSetHandler resultSetHandler;// 使用傳入的實(shí)參替換SQL語(yǔ)句中的?protected final ParameterHandler parameterHandler;// 記錄執(zhí)行sql的executorprotected final Executor executor;protected final MappedStatement mappedStatement;// 分頁(yè)用到protected final RowBounds rowBounds;protected BoundSql boundSql;protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {this.configuration = mappedStatement.getConfiguration();this.executor = executor;this.mappedStatement = mappedStatement;this.rowBounds = rowBounds;this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.objectFactory = configuration.getObjectFactory();if (boundSql == null) { // issue #435, get the key before calculating the statement// 獲取主鍵generateKeys(parameterObject);boundSql = mappedStatement.getBoundSql(parameterObject);}this.boundSql = boundSql;this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);}@Overridepublic BoundSql getBoundSql() {return boundSql;}@Overridepublic ParameterHandler getParameterHandler() {return parameterHandler;}@Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement = null;try {// 初始化Statement對(duì)象 instantiateStatement由具體的子類對(duì)象實(shí)現(xiàn)statement = instantiateStatement(connection);// 設(shè)置超時(shí)時(shí)間setStatementTimeout(statement, transactionTimeout);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);}}protected abstract Statement instantiateStatement(Connection connection) throws SQLException;protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {Integer queryTimeout = null;if (mappedStatement.getTimeout() != null) {queryTimeout = mappedStatement.getTimeout();} else if (configuration.getDefaultStatementTimeout() != null) {queryTimeout = configuration.getDefaultStatementTimeout();}if (queryTimeout != null) {stmt.setQueryTimeout(queryTimeout);}StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);}protected void setFetchSize(Statement stmt) throws SQLException {Integer fetchSize = mappedStatement.getFetchSize();if (fetchSize != null) {stmt.setFetchSize(fetchSize);return;}Integer defaultFetchSize = configuration.getDefaultFetchSize();if (defaultFetchSize != null) {stmt.setFetchSize(defaultFetchSize);}}protected void closeStatement(Statement statement) {try {if (statement != null) {statement.close();}} catch (SQLException e) {//ignore}}protected void generateKeys(Object parameter) {KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();ErrorContext.instance().store();keyGenerator.processBefore(executor, mappedStatement, null, parameter);ErrorContext.instance().recall();}}2.1 ParameterHandler
在BaseStatementHandler中有一個(gè)對(duì)象叫ParameterHandler是用來(lái)設(shè)置參數(shù)規(guī)則的,當(dāng)StatementHandler調(diào)用prepare方法之后,接下來(lái)就是調(diào)用它來(lái)進(jìn)行設(shè)置參數(shù)。
public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps)throws SQLException;}getParameterObject是用來(lái)獲取參數(shù)的,setParameters(PreparedStatement ps)是用來(lái)設(shè)置參數(shù)的,相當(dāng)于對(duì)sql中所有的參數(shù)都執(zhí)行ps.setXXX(value);
ParameterHandler的默認(rèn)實(shí)現(xiàn)類是DefaultParameterHandler,其實(shí)現(xiàn)了接口中定義的兩個(gè)方法。
getParameterObject是獲取參數(shù),這個(gè)參數(shù)值就是你傳遞進(jìn)來(lái)的值,可能是個(gè)實(shí)體、map或單個(gè)基本類型數(shù)據(jù)。
@Override public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// 去除SQL中的參數(shù)映射列表List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() != ParameterMode.OUT) {//過(guò)濾掉存儲(chǔ)過(guò)程中的輸出參數(shù)Object value;//記錄綁定的實(shí)參值// 獲取參數(shù)名稱String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params//獲取參數(shù)值value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {//如果是單個(gè)值則直接賦值value = parameterObject;} else {// 獲取對(duì)象中相應(yīng)的屬性值或查找map對(duì)象中的值MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}//獲取參數(shù)值對(duì)應(yīng)的jdbc類型TypeHandler typeHandler = parameterMapping.getTypeHandler();JdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {//設(shè)置參數(shù)值和jdbc類型的對(duì)應(yīng)關(guān)系typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);} catch (SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}} }3. RoutingStatementHandler
/*** RoutingStatementHandler的主要功能就是根據(jù)mapper文件中的Statement的配置,生成一個(gè)對(duì)應(yīng)的StatementHandler* 可以是 SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler* 此類中的所有方法都是通過(guò)調(diào)用delegate對(duì)象的對(duì)應(yīng)方法實(shí)現(xiàn)的*/ public class RoutingStatementHandler implements StatementHandler {private final StatementHandler delegate;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());}} }4. SimpleStatementHandler
SimpleStatementHandler就是使用基本的Statement來(lái)執(zhí)行query、batch、update等操作,其實(shí)現(xiàn)還是比較簡(jiǎn)單的,SQL語(yǔ)句中是沒(méi)有占位符的,所以相應(yīng) 的paramterize()方法是空實(shí)現(xiàn)。
public class SimpleStatementHandler extends BaseStatementHandler {public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}@Overridepublic int update(Statement statement) throws SQLException {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();int rows;if (keyGenerator instanceof Jdbc3KeyGenerator) {// 生成主鍵statement.execute(sql, Statement.RETURN_GENERATED_KEYS);rows = statement.getUpdateCount();keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else if (keyGenerator instanceof SelectKeyGenerator) {statement.execute(sql);rows = statement.getUpdateCount();// 生成主鍵 keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else {statement.execute(sql);rows = statement.getUpdateCount();}return rows;}@Overridepublic void batch(Statement statement) throws SQLException {String sql = boundSql.getSql();statement.addBatch(sql);}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.<E>handleResultSets(statement);}@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.<E>handleCursorResultSets(statement);}@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {if (mappedStatement.getResultSetType() != null) {return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);} else {return connection.createStatement();}}@Overridepublic void parameterize(Statement statement) throws SQLException {// N/A}}5. PreparedStatementHandler
PreparedStatementHandler底層依賴PreparedStatement對(duì)象來(lái)完成數(shù)據(jù)庫(kù)的相關(guān)操作,在調(diào)用parameterize()方法完成SQL語(yǔ)句的參數(shù)綁定,代碼也比較簡(jiǎn)單。
public class PreparedStatementHandler extends BaseStatementHandler {public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}@Overridepublic int update(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();int rows = ps.getUpdateCount();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);return rows;}@Overridepublic void batch(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.addBatch();}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.<E> handleResultSets(ps);}@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.<E> handleCursorResultSets(ps);}@Overrideprotected 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);}}@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}}6. CallableStatementHandler
CallableStatementHandler實(shí)際就是使用CallableStatement來(lái)執(zhí)行SQL語(yǔ)句,當(dāng)然它執(zhí)行的是存儲(chǔ)過(guò)程。
public class CallableStatementHandler extends BaseStatementHandler {public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}@Overridepublic int update(Statement statement) throws SQLException {//用來(lái)調(diào)用存儲(chǔ)過(guò)程,它提供了對(duì)輸出和輸入/輸出參數(shù)的支持CallableStatement cs = (CallableStatement) statement;cs.execute();int rows = cs.getUpdateCount();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);resultSetHandler.handleOutputParameters(cs);return rows;}@Overridepublic void batch(Statement statement) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.addBatch();}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.execute();List<E> resultList = resultSetHandler.<E>handleResultSets(cs);resultSetHandler.handleOutputParameters(cs);return resultList;}@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.execute();Cursor<E> resultList = resultSetHandler.<E>handleCursorResultSets(cs);resultSetHandler.handleOutputParameters(cs);return resultList;}@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql = boundSql.getSql();if (mappedStatement.getResultSetType() != null) {return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);} else {return connection.prepareCall(sql);}}@Overridepublic void parameterize(Statement statement) throws SQLException {//注冊(cè)out參數(shù)registerOutputParameters((CallableStatement) statement);parameterHandler.setParameters((CallableStatement) statement);}private void registerOutputParameters(CallableStatement cs) throws SQLException {List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();for (int i = 0, n = parameterMappings.size(); i < n; i++) {ParameterMapping parameterMapping = parameterMappings.get(i);//處理存儲(chǔ)過(guò)程的INOUT和OUT if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {if (null == parameterMapping.getJdbcType()) {throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());} else {if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());} else {if (parameterMapping.getJdbcTypeName() == null) {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);} else {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());}}}}}}}?
總結(jié)
以上是生活随笔為你收集整理的mybatis源码阅读(六) ---StatementHandler了解一下的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: pdf合并成一个文件如何将pdf合并成一
- 下一篇: 如何在路由器上用命令行的方式设置ip地址