最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

前言

創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比鞍山網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式鞍山網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋鞍山地區(qū)。費(fèi)用合理售后完善,十多年實(shí)體公司更值得信賴。

SqlSession是Mybatis最重要的構(gòu)建之一,可以簡(jiǎn)單的認(rèn)為Mybatis一系列的配置目的是生成類似 JDBC生成的Connection對(duì)象的SqlSession對(duì)象,這樣才能與數(shù)據(jù)庫(kù)開啟“溝通”,通過SqlSession可以實(shí)現(xiàn)增刪改查(當(dāng)然現(xiàn)在更加推薦是使用Mapper接口形式),那么它是如何執(zhí)行實(shí)現(xiàn)的,這就是本篇博客所介紹的東西,其中會(huì)涉及到簡(jiǎn)單的源碼講解。

了解SqlSession的運(yùn)作原理是學(xué)習(xí)Mybatis插件的必經(jīng)之路,因?yàn)镸ybatis的插件會(huì)在SqlSession運(yùn)行過程中“插入”運(yùn)行,如果沒有很好理解的話,Mybatis插件可能會(huì)覆蓋相應(yīng)的源碼造成嚴(yán)重的問題。鑒于此,本篇博文盡量詳細(xì)介紹SqlSession運(yùn)作原理!

1、SqlSession簡(jiǎn)單介紹

(1)SqlSession簡(jiǎn)單原理介紹

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

映射器其實(shí)就是一個(gè)動(dòng)態(tài)代理對(duì)象,進(jìn)入到MapperMethod的execute方法就能簡(jiǎn)單找到SqlSession的刪除、更新、查詢、選擇方法,從底層實(shí)現(xiàn)來(lái)說(shuō):通過動(dòng)態(tài)代理技術(shù),讓接口跑起來(lái),之后采用命令模式,最后還是采用了SqlSession的接口方法(getMapper()方法等到Mapper)執(zhí)行SQL查詢(也就是說(shuō)Mapper接口方法的實(shí)現(xiàn)底層還是采用SqlSession接口方法實(shí)現(xiàn)的)。

注:以上雖然只是簡(jiǎn)單的描述,但實(shí)際上源碼相對(duì)復(fù)雜,下面將結(jié)合源碼進(jìn)行簡(jiǎn)單的介紹!

(2)SqlSession重要的四個(gè)對(duì)象

1)Execute:調(diào)度執(zhí)行StatementHandler、ParmmeterHandler、ResultHandler執(zhí)行相應(yīng)的SQL語(yǔ)句;

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

3)ParammeterHandler:處理SQL參數(shù);

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

2、SqlSession四大對(duì)象

(1)Execute執(zhí)行器:

 執(zhí)行器起到至關(guān)重要的作用,它是真正執(zhí)行Java與數(shù)據(jù)庫(kù)交互的東西,參與了整個(gè)SQL查詢執(zhí)行過程中。

1)主要有三種執(zhí)行器:簡(jiǎn)易執(zhí)行器SIMPLE(不配置就是默認(rèn)執(zhí)行器)、REUSE是一種重用預(yù)處理語(yǔ)句、BATCH批量更新、批量專用處理器

package org.apache.ibatis.session;

/**

* @author Clinton Begin

*/

public enum ExecutorType {

SIMPLE, REUSE, BATCH

}

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

首先,以SimpleExecutor為例,查看源碼我們得到如下幾點(diǎn)重要知識(shí)點(diǎn):

第一:Executor通過Configuration對(duì)象中newExecutor()方法中選擇相應(yīng)的執(zhí)行器生成

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {

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

}

executor = (Executor) interceptorChain.pluginAll(executor);

return executor;

}

注:最后interceptorChain.pluginAll()中執(zhí)行層層動(dòng)態(tài)代理,最后在可以在調(diào)用真正的Executor前可以修改插件代碼,這也就是為什么學(xué)會(huì)Mybatis的插件必須要知道SqlSession的運(yùn)行過程)

第二:在執(zhí)行器中StatementHandler是根據(jù)Configuration構(gòu)建的

public SimpleExecutor(Configuration configuration, Transaction transaction) {

super(configuration, transaction);

}

@Override

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {

Statement stmt = null;

try {

Configuration configuration = ms.getConfiguration();

StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

stmt = prepareStatement(handler, ms.getStatementLog());

return handler.update(stmt);

} finally {

closeStatement(stmt);

}

}

第三:Executor會(huì)執(zhí)行StatementHandler的prepare()方法進(jìn)行預(yù)編譯---->填入connection對(duì)象等參數(shù)---->再調(diào)用parameterize()方法設(shè)置參數(shù)---->完成預(yù)編譯

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

Statement stmt;

Connection connection = getConnection(statementLog);

stmt = handler.prepare(connection, transaction.getTimeout());

handler.parameterize(stmt);

return stmt;

}

總結(jié)以上繪制簡(jiǎn)單思維圖如下:

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

(2)StatementHanlder數(shù)據(jù)庫(kù)會(huì)話器

1)作用:簡(jiǎn)單來(lái)說(shuō)就是專門處理數(shù)據(jù)庫(kù)會(huì)話。詳細(xì)來(lái)說(shuō)就是進(jìn)行預(yù)編譯并且調(diào)用ParameterHandler的setParameters()方法設(shè)置參數(shù)。

2)數(shù)據(jù)庫(kù)會(huì)話器主要有三種:SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分別對(duì)應(yīng)Executor的三種執(zhí)行器(SIMPLE、REUSE、BATCH)

我們從上述Executor的prepareStatement()方法中調(diào)用了StatementHandler的parameterize()開始一步步地查看源碼,如下得到幾點(diǎn)重要的知識(shí)點(diǎn):小編整理了一套java架構(gòu)資料和BAT面試題,加659270626領(lǐng)取,限前20名,先到先得。

第一:StatementHandler的生成是由Configuration方法中newStatementHandler()方法生成的,但是正在創(chuàng)建的是實(shí)現(xiàn)了StatementHandler接口的RoutingStatementHandler對(duì)象

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的通過適配器模式找到對(duì)應(yīng)(根據(jù)上下文)的StatementHandler執(zhí)行的,并且有SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler,分別對(duì)應(yīng)Executor的三種執(zhí)行器(SIMPLE、REUSE、BATCH)

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

}

之后主要以PrepareStatementHandler為例,我們觀察到:它是實(shí)現(xiàn)BaseStatementHandler接口的,最后BaseStatementHandler又是實(shí)現(xiàn)StatementHandler接口的

public class PreparedStatementHandler extends BaseStatementHandler

......

public abstract class BaseStatementHandler implements StatementHandler

它主要有三種方法:prepare、parameterize和query,我們查看源碼:

第三:在BaseStatementHandler中重寫prepare()方法,instantiateStatement()方法完成預(yù)編譯,之后設(shè)置一些基礎(chǔ)配置(獲取最大行數(shù),超時(shí))

@Override

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {

ErrorContext.instance().sql(boundSql.getSql());

Statement statement = null;

try {

statement = instantiateStatement(connection);

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

}

}

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

@Override

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()預(yù)編譯完成之后,Executor會(huì)調(diào)用parameterize()方法(在上面的Executor部分中已經(jīng)做了介紹),實(shí)際上是調(diào)用ParameterHandler的setParameters()方法

@Override

public void parameterize(Statement statement) throws SQLException {

parameterHandler.setParameters((PreparedStatement) statement);

}

(3)ParameterHandler參數(shù)處理器

作用:對(duì)預(yù)編譯中參數(shù)進(jìn)行設(shè)置,如果有配置typeHandler,自然會(huì)對(duì)注冊(cè)的typeHandler對(duì)參數(shù)進(jìn)行處理

查看并學(xué)習(xí)源碼,得到以下幾點(diǎn)重要知識(shí)點(diǎn):

第一:Mybatis提供了ParamterHandler的默認(rèn)實(shí)現(xiàn)類DefalutParameterHandler

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

public interface ParameterHandler {

Object getParameterObject();

void setParameters(PreparedStatement ps)

throws SQLException;

}

其中:getParameterObject是返回參數(shù)對(duì)象,setParameters()是設(shè)置預(yù)編譯參數(shù))

第二:從parameterObject中取到參數(shù),然后使用typeHandler(注冊(cè)在Configuration中)進(jìn)行參數(shù)處理:

@Override

public void setParameters(PreparedStatement ps) {

ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());

List parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) {

for (int i = 0; i < parameterMappings.size(); i++) {

ParameterMapping parameterMapping = parameterMappings.get(i);

if (parameterMapping.getMode() != ParameterMode.OUT) {

Object value;

String propertyName = parameterMapping.getProperty();

if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params

value = boundSql.getAdditionalParameter(propertyName);

} else if (parameterObject == null) {

value = null;

} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

value = parameterObject;

} else {

MetaObject metaObject = configuration.newMetaObject(parameterObject);

value = metaObject.getValue(propertyName);

}

TypeHandler typeHandler = parameterMapping.getTypeHandler();

JdbcType jdbcType = parameterMapping.getJdbcType();

if (value == null && jdbcType == null) {

jdbcType = configuration.getJdbcTypeForNull();

}

try {

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

}

}

}

}

}

(4)ResultSetHandler結(jié)果集處理器

作用:很簡(jiǎn)單,就是組裝結(jié)果返回結(jié)果集

第一:ResultSetHandler接口,handlerResultSets()是包裝并返回結(jié)果集的,handleOutputParameters()是處理存儲(chǔ)過程輸出參數(shù)的

public interface ResultSetHandler {

List handleResultSets(Statement stmt) throws SQLException;

Cursor handleCursorResultSets(Statement stmt) throws SQLException;

void handleOutputParameters(CallableStatement cs) throws SQLException;

第二:Mybatis提供了默認(rèn)的ResultSetHandler實(shí)現(xiàn)類DefaultResultSetHandler,其中重點(diǎn)是handlerResultSets()的實(shí)現(xiàn),但是其實(shí)現(xiàn)過程比較復(fù)雜,這里不過多介紹(emmmmm....個(gè)人目前能力還達(dá)理解,仍需努力)

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

第三:在Executor中doQuery()方法返回了封裝的結(jié)果集

@Override

public List 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(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

stmt = prepareStatement(handler, ms.getStatementLog());

return handler.query(stmt, resultHandler);

} finally {

closeStatement(stmt);

}

}

第四:實(shí)際上是返回結(jié)果是調(diào)用了resultSetHandler的handleResultSets()方法

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

return resultSetHandler. handleResultSets(ps);

}

3、SqlSession運(yùn)行總結(jié)

(1)文字總結(jié)

SqlSession的運(yùn)行主要是依靠Executor執(zhí)行器調(diào)用(調(diào)度)StatementHandler、parameterHanlder、ResultSetHandler,Executor首先通過創(chuàng)建StamentHandler執(zhí)行預(yù)編譯并設(shè)置參數(shù)運(yùn)行,而整個(gè)過程需要如下幾步才能完成:

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

Statement stmt;

Connection connection = getConnection(statementLog);

stmt = handler.prepare(connection, transaction.getTimeout());

handler.parameterize(stmt);

return stmt;

}

1)prepare預(yù)編譯SQL

由適配模式生成的RoutingStatementHandler根據(jù)上下文選擇生成三種相應(yīng)的XXXStatementHandler;

在生成的XXXStatementHandler內(nèi)部instantiateStatement()方法執(zhí)行底層JDBC的prepareStatement()方法完成預(yù)編譯

2)parameterize設(shè)置參數(shù)

默認(rèn)是DefaultParameterHandler(實(shí)現(xiàn)了parameterHandler接口)中setParameter()方法完成參數(shù)配置,其中參數(shù)從ParameterObject中取出,交給typeHandler處理

3)doUpdate/doQuery執(zhí)行SQL

返回的結(jié)果通過默認(rèn)的DefaultResultSetHandler(實(shí)現(xiàn)了ResultSetHandler接口)封裝

(2)運(yùn)行圖總結(jié)

1)SqlSession內(nèi)部總運(yùn)行圖

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

2)prepare()方法運(yùn)行圖: 3)parameterize()方法運(yùn)行圖

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理

一文讓你秒懂Mybatis的SqlSession運(yùn)行原理


本文標(biāo)題:一文讓你秒懂Mybatis的SqlSession運(yùn)行原理
分享URL:http://fisionsoft.com.cn/article/gocpec.html