精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

流程解耦,封裝結(jié)果集處理器

開發(fā) 前端
這一章節(jié)的整個(gè)功能實(shí)現(xiàn),都在圍繞流程的解耦進(jìn)行處理,將對(duì)象的參數(shù)解析和結(jié)果封裝都進(jìn)行拆解,通過這樣的方式來分配各個(gè)模塊的單一職責(zé),不讓一個(gè)類的方法承擔(dān)過多的交叉功能。

一、前言

碼農(nóng),如何為自己的職業(yè)生涯續(xù)期?

上班就像打怪升級(jí),拿著一把西瓜刀,從南天門砍到北天門。但時(shí)間長了,怪越來越兇了,西瓜刀也不得手了。咋辦,在游戲里大家肯定是想辦法換裝備了、買武器了、學(xué)技能了,這樣才能有機(jī)會(huì)打通更多的關(guān)卡。

其實(shí)我們作為程序員上班也是一樣的,如果一直都以為這點(diǎn)技術(shù)夠?qū)憣慍RUD就夠了,反正現(xiàn)在還能應(yīng)付的了。但3年后呢、5年后呢,總有一天你的技術(shù)根本沒法滿足公司對(duì)你現(xiàn)階段的要求,最簡單的CRUD也早已交給了曾經(jīng)年輕的另外的你。

有人說:“程序員不是技術(shù)牛就能一直行!” 但其實(shí)技術(shù)牛就是行,當(dāng)你牛到一定的階段,解決別人解決不了的問題,處理別人處理的不了的方案,蝎子粑粑獨(dú)一份,誰又能攔得住你呢。在哪里工作都是你自己來定的,你只管技術(shù)牛,就能橫著走。

二、目標(biāo)

延續(xù)著上一章節(jié),我們對(duì)參數(shù)的封裝和調(diào)用,使用了策略模式進(jìn)行解耦處理,本章節(jié)將對(duì)執(zhí)行完查詢的結(jié)果進(jìn)行封裝處理。而不是像我們前面章節(jié)那樣粗魯?shù)呐袛喾庋b,因?yàn)檫@樣的方式既不能滿足不同類型的優(yōu)雅擴(kuò)展,也不以為維護(hù)迭代。如圖 11-1 所示

圖片

圖 11-1 簡單的結(jié)果集處理

  • 對(duì)于結(jié)果集的封裝處理,其實(shí)核心在于我們拿到了 Mapper XML 中所配置的返回類型,解析后把從數(shù)據(jù)庫查詢到的結(jié)果,反射到類型實(shí)例化的對(duì)象上。
  • 那么這個(gè)過程中,我們需要滿足不同返回類型的處理,比如Long、Double、String、Date等,都要一一與數(shù)據(jù)庫的類型匹配,與此同時(shí),返回的結(jié)果可能是一個(gè)普通的基本類型,也可能是我們封裝后的對(duì)象類型。并這個(gè)結(jié)果查詢也不一定只是一條記錄,還可能是多條記錄。那么為了更好的處理這些不同情況下的問題,就需要對(duì)流程進(jìn)行分治和實(shí)現(xiàn),以及在過程中進(jìn)行抽象化的解耦,這樣才能滿足于我們把不同的返回信息訴求,封裝到對(duì)象里去。分治、抽象和知識(shí),來自于人月神話中的康威定律,它是系統(tǒng)設(shè)計(jì)的第一原則。

三、設(shè)計(jì)

在我們使用  JDBC 獲取到查詢結(jié)果 ResultSet#getObject 可以獲取返回屬性值,但其實(shí) ResultSet 是可以按照不同的屬性類型進(jìn)行返回結(jié)果的,而不是都返回 Object 對(duì)象(如圖11-2 所示)。那么其實(shí)我們?cè)谏弦徽鹿?jié)中處理屬性信息時(shí)候,所開發(fā)的 TypeHandler 接口的實(shí)現(xiàn)類,就可以擴(kuò)充返回結(jié)果的方法,例如:LongTypeHandler#getResult、StringTypeHandler#getResult 等,這樣我們就可以使用策略模式非常明確的定位到返回的結(jié)果,而不需要進(jìn)行if判斷處理。

圖片

圖 11-2 返回類型

再有了這個(gè)目標(biāo)的前提下,就可以通過解析 XML 信息時(shí)封裝返回類型到映射器語句類中,MappedStatement#resultMaps 直到執(zhí)行完 SQL 語句,按照我們的返回結(jié)果參數(shù)類型,創(chuàng)建對(duì)象和使用 MetaObject 反射工具類填充屬性信息。詳細(xì)設(shè)計(jì)如圖 11-3 所示

圖片

圖 11-3 封裝結(jié)果集處理器

  • 首先我們?cè)诮馕?XML 語句解析構(gòu)建器中,添加一個(gè) MapperBuilderAssistant 映射器的助手類,方便我們對(duì)參數(shù)的統(tǒng)一包裝處理,按照職責(zé)歸屬的方式進(jìn)行細(xì)分解耦。通過這樣的方式在 MapperBuilderAssistant#setStatementResultMap 中封裝返回結(jié)果信息,一般來說我們使用 Mybatis 配置返回對(duì)象的時(shí)候 ResultType 就能解決大部分問題,而不需要都是配置一個(gè) ResultMap 映射結(jié)果。但這里的設(shè)計(jì)其實(shí)是把 ResultType 也按照一個(gè) ResultMap 的方式進(jìn)行封裝處理,這樣統(tǒng)一一個(gè)標(biāo)準(zhǔn)的方式進(jìn)行包裝,做了到適配的效果,也更加方便后面對(duì)這樣的參數(shù)進(jìn)行統(tǒng)一使用。
  • 接下來就是執(zhí)行 JDBC 操作查詢到數(shù)據(jù)以后,對(duì)結(jié)果的封裝。那么在 DefaultResultSetHandler 返回結(jié)果處理中,首先會(huì)按照我們已經(jīng)解析的到的 ResultType 進(jìn)行對(duì)象的實(shí)例化。實(shí)例化對(duì)象以后再根據(jù)解析出來對(duì)象中參數(shù)的名稱獲取對(duì)應(yīng)的類型,在根據(jù)類型找到 TypeHandler 接口實(shí)現(xiàn)類,也就是我們前面提到的 LongTypeHandler、StringTypeHandler,因?yàn)橥ㄟ^這樣的方式,可以避免 if···else 的判斷,而是直接O(1)時(shí)間復(fù)雜度定位到對(duì)應(yīng)的類型處理器,在不同的類型處理器中返回結(jié)果信息。最終拿到結(jié)果再通過前面章節(jié)已經(jīng)開發(fā)過的 MetaObject 反射工具類進(jìn)行屬性信息的設(shè)置。metaObject.setValue(property, value)最終填充實(shí)例化并設(shè)置了屬性內(nèi)容的結(jié)果對(duì)象到上下文中,直至處理完成返回最終的結(jié)果數(shù)據(jù),以此處理完成。

四、實(shí)現(xiàn)

1. 工程結(jié)構(gòu)

mybatis-step-10
└── src
├── main
│ └── java
│ └── cn.bugstack.mybatis
│ ├── binding
│ ├── builder
│ │ ├── xml
│ │ │ ├── XMLConfigBuilder.java
│ │ │ ├── XMLMapperBuilder.java
│ │ │ └── XMLStatementBuilder.java
│ │ ├── BaseBuilder.java
│ │ ├── MapperBuilderAssistant.java
│ │ ├── ParameterExpression.java
│ │ ├── SqlSourceBuilder.java
│ │ └── StaticSqlSource.java
│ ├── datasource
│ ├── executor
│ │ ├── resultset
│ │ │ └── ParameterHandler.java
│ │ ├── resultset
│ │ │ ├── DefaultResultContext.java
│ │ │ └── DefaultResultHandler.java
│ │ ├── resultset
│ │ │ ├── DefaultResultSetHandler.java
│ │ │ └── ResultSetHandler.java
│ │ │ └── ResultSetWrapper.java
│ │ ├── statement
│ │ │ ├── BaseStatementHandler.java
│ │ │ ├── PreparedStatementHandler.java
│ │ │ ├── SimpleStatementHandler.java
│ │ │ └── StatementHandler.java
│ │ ├── BaseExecutor.java
│ │ ├── Executor.java
│ │ └── SimpleExecutor.java
│ ├── io
│ ├── mapping
│ │ ├── BoundSql.java
│ │ ├── Environment.java
│ │ ├── MappedStatement.java
│ │ ├── ParameterMapping.java
│ │ ├── ResultMap.java
│ │ ├── ResultMapping.java
│ │ ├── SqlCommandType.java
│ │ └── SqlSource.java
│ ├── parsing
│ ├── reflection
│ ├── scripting
│ ├── session
│ │ ├── defaults
│ │ │ ├── DefaultSqlSession.java
│ │ │ └── DefaultSqlSessionFactory.java
│ │ ├── Configuration.java
│ │ ├── ResultContext.java
│ │ ├── ResultHandler.java
│ │ ├── RowBounds.java
│ │ ├── SqlSession.java
│ │ ├── SqlSessionFactory.java
│ │ ├── SqlSessionFactoryBuilder.java
│ │ └── TransactionIsolationLevel.java
│ ├── transaction
│ └── type
│ ├── BaseTypeHandler.java
│ ├── JdbcType.java
│ ├── LongTypeHandler.java
│ ├── StringTypeHandler.java
│ ├── TypeAliasRegistry.java
│ ├── TypeHandler.java
│ └── TypeHandlerRegistry.java
└── test
├── java
│ └── cn.bugstack.mybatis.test.dao
│ ├── dao
│ │ └── IUserDao.java
│ ├── po
│ │ └── User.java
│ └── ApiTest.java
└── resources
├── mapper
│ └──User_Mapper.xml
└── mybatis-config-datasource.xml

流程解耦,封裝結(jié)果集處理器核心類關(guān)系,如圖 11-4 所示

圖片

圖 11-4 封裝結(jié)果集處理器核心類關(guān)系

  • 在 XML 語句構(gòu)建器中使用映射構(gòu)建器助手,包裝映射器語句入?yún)ⅰ⒊鰠⒌姆庋b處理。通過此處功能職責(zé)的切割,滿足不同邏輯單元的擴(kuò)展。MapperBuilderAssistant#setStatementResultMap 處理 ResultType/ResultMap 的封裝信息。
  • 入?yún)⑿畔⒌慕馕鰰?huì)存放到映射語句 MappedStatement 類中,這樣隨著 DefaultSqlSession#selectOne 具體方法的執(zhí)行時(shí),就可以通過 statement 從配置項(xiàng)中獲取到對(duì)應(yīng)的 MappedStatement 信息,所以這里的設(shè)計(jì)是符合一個(gè)充血模型結(jié)構(gòu)的領(lǐng)域功能聚合。
  • 最后就是實(shí)現(xiàn)了 ResultSetHandler 結(jié)果集處理器接口的 DefaultResultSetHandler 實(shí)現(xiàn)類,對(duì)查詢結(jié)果的封裝處理,這里主要分為按照解析出來的 resultType 類型進(jìn)行實(shí)例化對(duì)象,之后根據(jù)對(duì)象的屬性信息尋找對(duì)應(yīng)的處理策略,避免if···else判斷的方式獲取對(duì)應(yīng)的結(jié)果,當(dāng)對(duì)象和屬性都準(zhǔn)備完畢后,就可以使用 MetaObject 元對(duì)象反射工具類進(jìn)行屬性填充,形成一個(gè)完整的結(jié)果對(duì)象,并寫入到結(jié)果上下文中 DefaultResultContext 返回。

2. 出參參數(shù)處理

鑒于對(duì) XML 語句構(gòu)建器中解析語句后的信息封裝會(huì)逐步增多,所以這里需要引入映射構(gòu)建器助手對(duì)類中方法的職責(zé)進(jìn)行劃分,降低一個(gè)方法塊內(nèi)的邏輯復(fù)雜度。這樣的方式也更加利于代碼的維護(hù)和擴(kuò)展。

2.1 結(jié)果映射封裝

熟悉使用 Mybatis 的讀者都清楚的知道,在一條語句配置中需要有包括一個(gè)返回類型的配置,這個(gè)返回類型可以是通過 resultType 配置,也可以使用  resultMap 進(jìn)行處理,而無論使用哪種方式其實(shí)最終都會(huì)被封裝成統(tǒng)一的 ResultMap 結(jié)果映射類。

那么一般我們配置 ResultMap 都是配置了字段的映射,所以實(shí)際的代碼開發(fā)中 ResultMap 還會(huì)包含 ResultMapping 也就是每一個(gè)字段的映射信息,包括:colum、javaType、jdbcType 等。由于本章節(jié)暫時(shí)還不涉及到 ResultMap 的使用,所以這里我們先只是建好基本的地基結(jié)構(gòu)就可以。

源碼詳見:cn.bugstack.mybatis.mapping.ResultMap

public class ResultMap {

private String id;
private Class<?> type;
private List<ResultMapping> resultMappings;
private Set<String> mappedColumns;

//...
}

ResultMap 就是一個(gè)簡單的返回結(jié)果信息映射類,并提供了建造者方法,方便外部使用。沒有太多的邏輯行為,具體可以參照源碼。

2.2 構(gòu)建器助手

MapperBuilderAssistant 構(gòu)建器助手專門為創(chuàng)建 MappedStatement 映射語句類而服務(wù)的,在這個(gè)類中封裝了入?yún)⒑统鰠⒌挠成洹⒁约鞍堰@些配置信息寫入到 Configuration 配置項(xiàng)中。

源碼詳見:cn.bugstack.mybatis.builder.MapperBuilderAssistant

public class MapperBuilderAssistant extends BaseBuilder {

/**
* 添加映射器語句
*/
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
SqlCommandType sqlCommandType,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
LanguageDriver lang
) {
// 給id加上namespace前綴:cn.bugstack.mybatis.test.dao.IUserDao.queryUserInfoById
id = applyCurrentNamespace(id, false);
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlCommandType, sqlSource, resultType);

// 結(jié)果映射,給 MappedStatement#resultMaps
setStatementResultMap(resultMap, resultType, statementBuilder);

MappedStatement statement = statementBuilder.build();
// 映射語句信息,建造完存放到配置項(xiàng)中
configuration.addMappedStatement(statement);

return statement;
}

private void setStatementResultMap(
String resultMap,
Class<?> resultType,
MappedStatement.Builder statementBuilder) {
List<ResultMap> resultMaps = new ArrayList<>();
/*
* 通常使用 resultType 即可滿足大部分場景
* <select id="queryUserInfoById" resultType="cn.bugstack.mybatis.test.po.User">
* 使用 resultType 的情況下,Mybatis 會(huì)自動(dòng)創(chuàng)建一個(gè) ResultMap,基于屬性名稱映射列到 JavaBean 的屬性上。
*/
ResultMap.Builder inlineResultMapBuilder = new ResultMap.Builder(
configuration,
statementBuilder.id() + "-Inline",
resultType,
new ArrayList<>());
resultMaps.add(inlineResultMapBuilder.build());
statementBuilder.resultMaps(resultMaps);
}

}
  • 在映射構(gòu)建器助手中,提供了添加映射器語句的方法,在這個(gè)方法中更加標(biāo)準(zhǔn)的封裝了入?yún)⒑统鰠⑿畔ⅰH绻@些內(nèi)容全部都堆砌到 XMLStatementBuilder 語句構(gòu)建器的解析中,就會(huì)顯得非常臃腫不易于維護(hù)了
  • 在 MapperBuilderAssistant#setStatementResultMap 方法中,其實(shí)它只是一個(gè)非常簡單的結(jié)果映射建造的過程,無論是否為 ResultMap 都會(huì)進(jìn)行這樣的封裝處理。并最終把創(chuàng)建的信息寫入到 MappedStatement 映射語句類中。

2.3 調(diào)用助手類

接下來我們就可以清理 XMLStatementBuilder 語句構(gòu)建器中解析后,映射語句類的構(gòu)建和存放處理流程。通過使用助手類,統(tǒng)一封裝參數(shù)信息。

源碼詳見:cn.bugstack.mybatis.builder.xml.XMLStatementBuilder

圖片

  • 與上一章節(jié)相比,對(duì)于這部分的解析后的結(jié)果處理的職責(zé)內(nèi)容,劃分到了新增加的助手類中,這種實(shí)現(xiàn)方式在 Mybatis 的源碼中還是非常多的,大部分的內(nèi)容處理,都會(huì)提供一個(gè)助手類進(jìn)行操作。

3. 查詢結(jié)果封裝

從 DefaultSqlSession 調(diào)用 Executor 語句執(zhí)行器,一直到 PreparedStatementHandler 預(yù)處理語句處理,最后就是 DefaultResultSetHandler 結(jié)果信息的封裝。

前面章節(jié)對(duì)此處的封裝處理,并沒有解耦的操作,只是簡單的 JDBC 使用通過查詢結(jié)果,反射處理返回信息就結(jié)束了。如果是使用這樣的一個(gè)簡單的 if···else 面向過程方式進(jìn)行開發(fā),那么后續(xù)所需要滿足 Mybatis 的全部封裝對(duì)象功能,就會(huì)變得特別吃力,一個(gè)方法塊也會(huì)越來越大。

所以這一部分的內(nèi)容處理是需要被解耦,分為;對(duì)象的實(shí)例化、結(jié)果信息的封裝、策略模式的處理、寫入上下文返回等操作,只有通過這樣的解耦流程,才能更加方便的擴(kuò)展流程不同節(jié)點(diǎn)中的各類需求。

源碼詳見:cn.bugstack.mybatis.executor.resultset.DefaultResultSetHandler#handleResultSet

圖片

這是一套結(jié)果封裝的核心處理流程,包括創(chuàng)建處理器、封裝數(shù)據(jù)和保存結(jié)果,接下來就分別介紹下這塊代碼的具體實(shí)現(xiàn)。

3.1 結(jié)果集收集器

源碼詳見:cn.bugstack.mybatis.executor.result.DefaultResultHandler

public class DefaultResultHandler implements ResultHandler {

private final List<Object> list;
/**
* 通過 ObjectFactory 反射工具類,產(chǎn)生特定的 List
*/
@SuppressWarnings("unchecked")
public DefaultResultHandler(ObjectFactory objectFactory) {
this.list = objectFactory.create(List.class);
}

@Override
public void handleResult(ResultContext context) {
list.add(context.getResultObject());
}

}

這里封裝了一個(gè)非常簡單的結(jié)果集對(duì)象,默認(rèn)情況下都會(huì)寫入到這個(gè)對(duì)象的 list 集合中。

3.2 對(duì)象創(chuàng)建

在處理封裝數(shù)據(jù)的過程中,包括根據(jù) resultType 使用反射工具類 ObjectFactory#create 方法創(chuàng)建出 Bean 對(duì)象。這個(gè)過程會(huì)根據(jù)不同的類型進(jìn)行創(chuàng)建,不過暫時(shí)我們這里只是普通對(duì)象,所以不會(huì)填充太多的代碼,避免擾亂讀者的重點(diǎn)核心內(nèi)容的學(xué)習(xí)

調(diào)用鏈路:handleResultSet->handleRowValuesForSimpleResultMap->getRowValue->createResultObject

源碼詳見:cn.bugstack.mybatis.executor.resultset.DefaultResultSetHandler#createResultObject

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException {
final Class<?> resultType = resultMap.getType();
final MetaClass metaType = MetaClass.forClass(resultType);
if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
// 普通的Bean對(duì)象類型
return objectFactory.create(resultType);
}
throw new RuntimeException("Do not know how to create an instance of " + resultType);
}
  • 對(duì)于這樣的普通對(duì)象,只需要使用反射工具類就可以實(shí)例化對(duì)象了,不過這個(gè)時(shí)候?qū)傩孕畔⑦€沒有填充。其實(shí)和我們使用的 clazz.newInstance(); 也是一樣的效果

3.3 屬性填充

對(duì)象實(shí)例化完成后,就是根據(jù) ResultSet 獲取出對(duì)應(yīng)的值填充到對(duì)象的屬性中,但這里需要注意,這個(gè)結(jié)果的獲取來自于 TypeHandler#getResult 接口新增的方法,由不同的類型處理器實(shí)現(xiàn),通過這樣的策略模式設(shè)計(jì)方式就可以巧妙的避免 if···else 的判斷處理。

圖片

圖 11-7 使用策略模式,獲取返回結(jié)果

源碼詳見:cn.bugstack.mybatis.executor.resultset.DefaultResultSetHandler#applyAutomaticMappings

圖片

  • columnName 是屬性名稱,根據(jù)屬性名稱,按照反射工具類從對(duì)象中獲取對(duì)應(yīng)的 properyType 屬性類型,之后再根據(jù)類型獲取到 TypeHandler 類型處理器。有了具體的類型處理器,在獲取每一個(gè)類型處理器下的結(jié)果內(nèi)容就更加方便了。
  • 獲取屬性值后,再使用 MetaObject 反射工具類設(shè)置屬性值,一次循環(huán)設(shè)置完成以后,這樣一個(gè)完整的結(jié)果信息 Bean 對(duì)象就可以返回了。返回后寫入到 DefaultResultContext#nextResultObject 上下文中

五、測試

1. 事先準(zhǔn)備

1.1 創(chuàng)建庫表

創(chuàng)建一個(gè)數(shù)據(jù)庫名稱為 mybatis 并在庫中創(chuàng)建表 user 以及添加測試數(shù)據(jù),如下:

CREATE TABLE
USER
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
userId VARCHAR(9) COMMENT '用戶ID',
userHead VARCHAR(16) COMMENT '用戶頭像',
createTime TIMESTAMP NULL COMMENT '創(chuàng)建時(shí)間',
updateTime TIMESTAMP NULL COMMENT '更新時(shí)間',
userName VARCHAR(64),
PRIMARY KEY (id)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user (id, userId, userHead, createTime, updateTime, userName) values (1, '10001', '1_04', '2022-04-13 00:00:00', '2022-04-13 00:00:00', '小傅哥');

1.2 配置數(shù)據(jù)源

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
  • 通過mybatis-config-datasource.xml 配置數(shù)據(jù)源信息,包括:driver、url、username、password
  • 在這里 dataSource 可以按需配置成 DRUID、UNPOOLED 和 POOLED 進(jìn)行測試驗(yàn)證。

1.3 配置Mapper

<select id="queryUserInfoById" parameterType="java.lang.Long" resultType="cn.bugstack.mybatis.test.po.User">
SELECT id, userId, userName, userHead
FROM user
where id = #{id}
</select>
  • 這部分暫時(shí)不需要調(diào)整,目前還只是一個(gè)入?yún)⒌念愋偷膮?shù),后續(xù)我們?nèi)客晟七@部分內(nèi)容以后,則再提供更多的其他參數(shù)進(jìn)行驗(yàn)證。

2. 單元測試

@Before
public void init() throws IOException {
// 1. 從SqlSessionFactory中獲取SqlSession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));
sqlSession = sqlSessionFactory.openSession();
}

@Test
public void test_queryUserInfoById() {
// 1. 獲取映射器對(duì)象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 2. 測試驗(yàn)證:基本參數(shù)
User user = userDao.queryUserInfoById(1L);
logger.info("測試結(jié)果:{}", JSON.toJSONString(user));
}
  • 這里我們只測試一個(gè)查詢結(jié)果即可,返回的類型是一個(gè)自定義的對(duì)象類型。

測試結(jié)果

圖片

12:39:17.321 [main] INFO  c.b.mybatis.builder.SqlSourceBuilder - 構(gòu)建參數(shù)映射 property:id propertyType:class java.lang.Long
12:39:17.321 [main] INFO c.b.mybatis.builder.SqlSourceBuilder - 構(gòu)建參數(shù)映射 property:userId propertyType:class java.lang.String
12:39:17.382 [main] INFO c.b.m.s.defaults.DefaultSqlSession - 執(zhí)行查詢 statement:cn.bugstack.mybatis.test.dao.IUserDao.queryUserInfoById parameter:1
12:39:17.684 [main] INFO c.b.m.s.d.DefaultParameterHandler - 根據(jù)每個(gè)ParameterMapping中的TypeHandler設(shè)置對(duì)應(yīng)的參數(shù)信息 value:1
12:39:17.728 [main] INFO cn.bugstack.mybatis.test.ApiTest - 測試結(jié)果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小傅哥"}

Process finished with exit code 0
  • 通過 DefaultResultSetHandler 結(jié)果處理器的功能解耦和實(shí)現(xiàn),已經(jīng)可以正常查詢和返回對(duì)應(yīng)的對(duì)象信息了,后續(xù)其他內(nèi)容的擴(kuò)展也可以基于這個(gè)基座進(jìn)行處理。

六、總結(jié)

  • 這一章節(jié)的整個(gè)功能實(shí)現(xiàn),都在圍繞流程的解耦進(jìn)行處理,將對(duì)象的參數(shù)解析和結(jié)果封裝都進(jìn)行拆解,通過這樣的方式來分配各個(gè)模塊的單一職責(zé),不讓一個(gè)類的方法承擔(dān)過多的交叉功能。
  • 那么我們?cè)诮Y(jié)合這樣的思想和設(shè)計(jì),反復(fù)閱讀和動(dòng)手實(shí)踐中,來學(xué)習(xí)這樣的代碼設(shè)計(jì)和開發(fā)過程,都能為我們以后實(shí)際開發(fā)業(yè)務(wù)代碼時(shí)候帶來參考建議,避免總是把所有的流程都寫到一個(gè)類或者方法中。
  • 到本章節(jié)全核心流程基本就串聯(lián)清楚了,再有的就是一些功能的拓展,比如支持更多的參數(shù)類型,以及添加除了 Select 以外的其他操作,還有一些緩存數(shù)據(jù)的使用等,后面章節(jié)將在這些內(nèi)容中,摘取一些核心的設(shè)計(jì)和實(shí)現(xiàn)進(jìn)行講解,讓讀者吸收更多的設(shè)計(jì)技巧。
責(zé)任編輯:武曉燕 來源: bugstack蟲洞棧
相關(guān)推薦

2022-09-02 08:23:12

軟件開發(fā)解耦架構(gòu)

2013-09-16 10:19:08

htmlcssJavaScript

2016-11-30 15:30:42

架構(gòu)工具和方案

2023-03-03 08:12:07

設(shè)計(jì)模式語言

2020-11-20 15:22:32

架構(gòu)運(yùn)維技術(shù)

2024-03-08 16:27:22

領(lǐng)域事件DDD項(xiàng)目跨層解耦

2025-05-20 07:13:22

Spring異步解耦Event

2021-03-10 05:50:06

IOCReact解耦組件

2014-09-09 09:49:59

2009-03-01 21:30:46

Mac OS X 10Nehalem處理器

2022-04-15 11:46:09

輕量系統(tǒng)解耦鴻蒙操作系統(tǒng)

2025-08-29 12:22:59

2018-04-18 08:47:17

Alluxio構(gòu)建存儲(chǔ)

2009-07-30 18:48:06

多核六核處理器

2009-07-30 09:08:08

多核處理器英特爾AMD

2017-12-26 15:52:31

MQ互聯(lián)網(wǎng)耦合

2022-12-28 07:45:17

2022-05-05 08:43:22

SQL執(zhí)行器參數(shù)

2017-11-15 09:32:27

解耦戰(zhàn)術(shù)架構(gòu)

2015-09-02 14:19:32

英特爾酷睿處理器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

亚洲日本国产精品| 国产成人免费在线观看视频| 操喷在线视频| 成人一级片在线观看| 久久久久久久久久久av| 精品无码人妻少妇久久久久久| 天堂亚洲精品| 成人激情综合网站| 国产成人精彩在线视频九色| 超碰caoprom| 国产精品极品美女在线观看| 国产精品伦一区二区三级视频| 成人综合网网址| 国产亚洲精品码| 啪啪国产精品| 欧美女孩性生活视频| 99久久99久久精品| 精品国产亚洲av麻豆| 亚洲国产日韩在线| 亚洲欧美国产制服动漫| 久久久久久三级| 91精品久久久| 91视频在线看| 国产在线视频不卡| 日韩av在线电影| 日韩激情图片| 欧美高清视频在线高清观看mv色露露十八 | 精品污污网站免费看| 久久精品在线免费视频| 天堂中文在线看| 精品一区二区三区不卡| 亚洲 日韩 国产第一| 人成免费在线视频| 日本妇女一区| 日韩欧美精品三级| 91视频免费版污| 最新超碰在线| 日本一区免费视频| 国产伦精品一区二区三区在线| 久久久蜜桃一区二区| 国产综合视频| 色偷偷9999www| 国产黄色网址在线观看| 成人国产一区| 色狠狠综合天天综合综合| 久久这里只有精品18| 在线看黄色av| 26uuu成人网一区二区三区| 51午夜精品| 在线观看视频中文字幕| 香蕉成人久久| 午夜精品久久久久久99热软件| 99成人在线观看| 国产成人三级| 亚洲精品网站在线播放gif| 久久6免费视频| 国产精品第一| 欧美天堂一区二区三区| 日韩一级在线免费观看| 2021天堂中文幕一二区在线观| 亚洲人成在线播放网站岛国 | 中文字幕天堂av| 大伊香蕉精品在线品播放| 欧美电影免费提供在线观看| 韩国三级在线看| 粉嫩久久久久久久极品| 亚洲国产91色在线| 一本色道综合久久欧美日韩精品 | 中国人与牲禽动交精品| 亚洲天堂最新地址| 欧美高清视频手机在在线| 久久网福利资源网站| 欧美激情一区二区视频| 99亚洲视频| 国产成人激情视频| 国产有码在线观看| 成人午夜看片网址| 欧美日韩在线一区二区三区| av网站大全在线观看| 亚洲情趣在线观看| 国产极品在线视频| xxxxx.日韩| 亚洲第一精品自拍| 无码国产69精品久久久久同性| 欧美大黑bbbbbbbbb在线| 欧美乱妇高清无乱码| 欧美啪啪小视频| 麻豆精品一区二区三区| 99在线视频播放| 美女做暖暖视频免费在线观看全部网址91| 久久久久国产精品厨房| 中文精品一区二区三区| 国产白丝在线观看| 欧美午夜视频网站| 国产国语老龄妇女a片| 九色精品91| 九九热99久久久国产盗摄| 亚洲日本视频在线观看| 国产麻豆成人传媒免费观看| 精品欧美日韩在线| 国产黄色在线免费观看| 岛国精品视频在线播放| 亚洲五月激情网| 亚洲自拍电影| 欧美日韩成人在线播放| 国产黄色免费视频| 成人福利视频网站| 亚洲在线色站| 亚洲天堂资源| 日韩精品一区二区三区蜜臀 | 99精品在线观看| 91精品国产91久久久久久久久| 中文字字幕在线观看| av电影一区二区| 特级黄色录像片| 成人看片在线观看| 日韩精品在线播放| 久久久久无码国产精品不卡| 三级精品在线观看| 韩日午夜在线资源一区二区| 成人在线直播| 欧美日韩一级片网站| 右手影院亚洲欧美| 日韩视频在线一区二区三区 | 国产真实有声精品录音| 国模私拍视频一区| 国产视频一区二区三区四区五区 | 久草网在线观看| 激情图片小说一区| 亚洲高清在线观看一区| 色8久久影院午夜场| 亚洲精品v天堂中文字幕| 青青草原免费观看| 国产尤物一区二区| 亚洲图片欧洲图片日韩av| 免费高清视频在线一区| 亚洲免费视频在线观看| 久久久久久久久久影院| 99在线视频精品| 日本欧美黄色片| 欧美aaaaaaaa牛牛影院| 2020久久国产精品| 五月天婷婷社区| 欧美性精品220| 性色av蜜臀av色欲av| 亚洲综合国产| 欧美1o一11sex性hdhd| 中文字幕在线看片| 亚洲美女久久久| 免费黄色片视频| 欧美极品xxx| 国产色视频在线播放| 日韩欧美精品| 成人在线精品视频| www.久久久久.com| 日韩欧美在线1卡| 欧美日韩国产精品一区二区三区| 国产精品69毛片高清亚洲| 特级西西人体www高清大胆| 国产一区二区三区视频在线| 久久偷看各类女兵18女厕嘘嘘| 国产手机精品视频| 一区二区三区不卡在线观看 | 综合亚洲色图| 国产精品极品美女在线观看免费 | 91精品国产九九九久久久亚洲| 天天综合天天色| 色婷婷激情综合| 亚洲 欧美 国产 另类| 精品一区二区日韩| 国产精品久久久久9999爆乳| 日本亚洲不卡| 国产男女猛烈无遮挡91| 制服丝袜中文字幕在线| 亚洲精品电影网在线观看| 国产成人麻豆免费观看| 成人免费在线视频| 欧美肉大捧一进一出免费视频| 日韩中文字幕区一区有砖一区| 色噜噜色狠狠狠狠狠综合色一| 国产成人无码一二三区视频| h片视频在线观看| 日韩av一卡二卡| 国产情侣呻吟对白高潮| 亚洲精品日日夜夜| 亚洲第九十七页| 久久国产乱子精品免费女| avav在线播放| 欧洲杯半决赛直播| 成人蜜桃视频| 亚洲爱爱视频| 久久久亚洲精品视频| 国产乱视频在线观看| 日韩精品一区二区三区视频播放 | 欧美午夜精品一区二区三区 | 欧美网站在线观看| 免费中文字幕日韩| 91视频国产观看| 天堂av手机在线| 99精品热视频只有精品10| 亚洲国产一区二区精品视频 | 97超碰在线视| 红桃成人av在线播放| 51午夜精品| 韩日精品一区| 欧美又大又粗又长| 影音先锋男人在线资源| 国产一区二区三区网站| 日韩一级片免费| 欧美一区二区三区免费大片| 毛片基地在线观看| 亚洲一区二区视频| 日本午夜在线观看| 国产校园另类小说区| 亚洲成a人无码| 久久爱www久久做| 国产天堂在线播放| 国产精品久久久久久模特| 国产欧美123| 先锋资源久久| 婷婷精品国产一区二区三区日韩| 九色丨蝌蚪丨成人| 亚洲va欧美va在线观看| 久久精品99国产精| 欧美日韩一区二区三区视频播放| 成人av影视在线| 国产精品国产亚洲精品| 国产免费一区二区三区香蕉精| 日韩免费va| 欧美专区中文字幕| 日本黄色免费在线| 国内精品久久久久久| 性爱视频在线播放| 免费97视频在线精品国自产拍| 亚洲欧美视频一区二区| 在线观看日韩欧美| 国产高清视频在线观看| 亚洲人成网站999久久久综合| 亚洲欧美丝袜中文综合| 日韩的一区二区| 熟妇高潮一区二区三区| 亚洲精品大尺度| 香蕉久久国产av一区二区| 亚洲国产日韩精品在线| 色欲av永久无码精品无码蜜桃| 日韩精品一区二区三区中文不卡| 久久精品日产第一区二区三区乱码| 亚洲精品白浆| 欧美日韩福利在线观看| 国产视频在线播放| 久久九九国产精品怡红院| 精品孕妇一区二区三区| 久久久99久久精品女同性| 黄色在线免费看| 欧美成人免费小视频| 肉体视频在线| 午夜精品一区二区三区在线播放 | 国产精品狠色婷| 日本在线精品| 国产日韩欧美日韩| 国产高清亚洲| 国产精品视频500部| 亚洲不卡在线| 麻豆亚洲一区| 人人狠狠综合久久亚洲婷| 在线天堂一区av电影| 久久精品青草| 日韩在线视频在线| 亚洲视频1区| 狠狠躁狠狠躁视频专区| 国产中文字幕精品| 国产白袜脚足j棉袜在线观看| 92精品国产成人观看免费| 37p粉嫩大胆色噜噜噜| 日本一区二区三区高清不卡 | 欧美性猛交xxxxx水多| 日韩xxx视频| 欧美一卡二卡在线| 五月天婷婷视频| 日韩最新av在线| 成人免费一区二区三区牛牛| 日本sm极度另类视频| 日韩伦理一区二区| 国产一级二级三级精品| 国产一区网站| 青春草国产视频| 欧美aaa在线| av不卡中文字幕| 国产女人aaa级久久久级| 欧美黄色免费在线观看| 一本色道a无线码一区v| 国产黄色大片网站| 国产视频精品xxxx| 在线中文字幕视频观看| 热re91久久精品国99热蜜臀| 高清国产一区二区三区四区五区| 精品乱码一区二区三区| 99久久久国产精品美女| 北条麻妃69av| 国产高清亚洲一区| 色一情一交一乱一区二区三区 | 亚洲天堂手机| 亚洲一区二区三区毛片 | 亚洲 欧美 变态 另类 综合| 精品久久久久久久大神国产| 亚洲欧洲在线看| 欧美hdxxx| 国产女人18毛片水18精品| 一区二区美女| 国产精品videossex国产高清| 奇米色一区二区| 欧美色图亚洲激情| 亚洲国产视频一区| 国产精品无码久久av| 国产一区二区美女视频| 超碰97国产精品人人cao| 91在线高清视频| 第一会所sis001亚洲| 六月丁香婷婷在线| www.亚洲国产| 久久久无码精品亚洲国产| 欧美日韩aaaaaa| 888av在线| 国产精品91免费在线| 里番精品3d一二三区| 成人在线视频一区二区三区| 韩国三级在线一区| jizz18女人高潮| 色婷婷综合久久久久中文| 天天操天天操天天| 欧美激情伊人电影| 秋霞一区二区三区| 2021狠狠干| 国产麻豆成人传媒免费观看| 99久久久无码国产精品不卡| 在线观看一区二区视频| 色播色播色播色播色播在线| 97av在线视频免费播放| 国产精品chinese在线观看| 成人在线观看毛片| 狠狠久久亚洲欧美| 男人天堂资源网| 欧美精品xxxxbbbb| 黄色免费网站在线| 91久久国产精品| 欧美久久一级| 国产精品嫩草69影院| 一区二区不卡在线视频 午夜欧美不卡在| 国产精品久久久久久久免费| 久久精品亚洲热| 国产一精品一av一免费爽爽| 91九色国产ts另类人妖| 国产乱国产乱300精品| 亚洲欧美一区二区三区四区五区| 欧美一区二区精品在线| 欧美四级在线| 久久久99国产精品免费| 性色一区二区| 国产一二三四区在线| 欧美精品三级日韩久久| a级在线观看| 精品一区二区国产| 久久精品中文| 自拍偷拍第9页| 欧美一区二区女人| 国产91足控脚交在线观看| 国内精品**久久毛片app| 日日噜噜夜夜狠狠视频欧美人| 亚洲欧洲综合网| 日韩欧美黄色影院| 国产不卡人人| 亚洲mv在线看| 国产精品888| av网站中文字幕| 日韩亚洲欧美成人| 在线免费观看成人网| www.视频一区| 中文字幕一区二区三区四区视频| 久久综合色影院| 日日狠狠久久偷偷综合色| 九色91popny| 亚洲综合在线免费观看| 免费观看成年在线视频网站| 成人在线视频网站| 亚洲伊人网站| 日韩av手机在线免费观看| 亚洲精品美女久久久| 四虎成人精品一区二区免费网站| www.日本在线视频| 国产欧美一区二区三区在线看蜜臀| 国产免费av观看| 日本精品一区二区三区在线| 婷婷综合五月| av在线网站观看| 日韩一区二区三区视频在线| 婷婷六月国产精品久久不卡| 喜爱夜蒲2在线| 中日韩免费视频中文字幕| 好吊色视频一区二区| 国产精品日韩在线|