在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MyBatis的實(shí)現(xiàn)原理

lhl545545 ? 來(lái)源:電子發(fā)燒友網(wǎng) ? 2018-02-24 11:25 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

MyBatis的實(shí)現(xiàn)原理

mybatis底層還是采用原生jdbc來(lái)對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作的,只是通過(guò) SqlSessionFactory,SqlSession Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等幾個(gè)處理器封裝了這些過(guò)程

執(zhí)行器:Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

參數(shù)處理器: ParameterHandler (getParameterObject, setParameters

結(jié)構(gòu)處理器 ResultSetHandler (handleResultSets, handleOutputParameters)

sql查詢處理器:StatementHandler (prepare, parameterize, batch, update, query)

其中StatementHandler用通過(guò)ParameterHandler與ResultHandler分別進(jìn)行參數(shù)預(yù)編譯 與結(jié)果處理。而ParameterHandler與ResultHandler都使用TypeHandler進(jìn)行映射。如下圖:

MyBatis的實(shí)現(xiàn)原理

Mybatis工作過(guò)程

通過(guò)讀mybatis的源碼進(jìn)行分析mybatis的執(zhí)行操作的整個(gè)過(guò)程,我們通過(guò)debug調(diào)試就可以知道Mybatis每一步做了什么事,我先把debug每一步結(jié)果 截圖,然后在分析這個(gè)流程。

第一步:讀取配置文件,形成InputStream

1 創(chuàng)建SqlSessionFacotry的過(guò)程

MyBatis的實(shí)現(xiàn)原理

從debug調(diào)試看出 返回的 sqlSessionFactory 是DefaultSesssionFactory類型的,但是configuration此時(shí)已經(jīng)被初始化了。查看源碼后畫如下創(chuàng)建DefaultSessionFactory的時(shí)序圖:

MyBatis的實(shí)現(xiàn)原理

2 創(chuàng)建SqlSession的過(guò)程

MyBatis的實(shí)現(xiàn)原理

從debug調(diào)試 看出SqlSessinoFactory.openSession() 返回的sqlSession是 DefaultSession類型的,此SqlSession里包含一個(gè)Configuration的對(duì)象,和一個(gè)Executor對(duì)象。查看源碼后畫如下創(chuàng)建DefaultSession的時(shí)序圖:

MyBatis的實(shí)現(xiàn)原理

3 創(chuàng)建Mapper的過(guò)程

MyBatis的實(shí)現(xiàn)原理

從debug調(diào)試可以看出,mapper是一個(gè)Mapper代理對(duì)象,而且初始化了Configuration對(duì)象,Executor的對(duì)象。查看源碼后畫如下創(chuàng)建Mapper的時(shí)序圖:

MyBatis的實(shí)現(xiàn)原理

4 執(zhí)行CRUD過(guò)程

1 以select為例查看各步執(zhí)行的源碼

1.mapper.selectEmployeeList()其實(shí)是MapperProxy執(zhí)行invoke方法,此方法顯示是判斷Method的方法是不是Object的toString等方法如果不是就執(zhí)行MapperMethod

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 判斷Method的方法是不是Object的toString等方法

if(Object.class.equals(method.getDeclaringClass())) {

try {

return method.invoke(this, args);

} catch (Throwable var5) {

throw ExceptionUtil.unwrapThrowable(var5);

}

} else {

//判斷private final Map

MapperMethod mapperMethod = this.cachedMapperMethod(method);

return mapperMethod.execute(this.sqlSession, args);

}

}

//查詢一級(jí)緩存和設(shè)置一級(jí)緩存

private MapperMethod cachedMapperMethod(Method method) {

MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);

if(mapperMethod == null) {

mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());

this.methodCache.put(method, mapperMethod);

}

return mapperMethod;

}

經(jīng)過(guò)上面的調(diào)用后進(jìn)入MapperMethod里面執(zhí)行

//判斷sql命令類型

public Object execute(SqlSession sqlSession, Object[] args) {

Object param;

Object result;

if(SqlCommandType.INSERT == this.command.getType()) {

param = this.method.convertArgsToSqlCommandParam(args);

result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));

} else if(SqlCommandType.UPDATE == this.command.getType()) {

param = this.method.convertArgsToSqlCommandParam(args);

result = this.rowCountResult(sqlSession.update(this.command.getName(), param));

} else if(SqlCommandType.DELETE == this.command.getType()) {

param = this.method.convertArgsToSqlCommandParam(args);

result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));

} else if(SqlCommandType.SELECT == this.command.getType()) {

//我們測(cè)試的是select類型,則再判斷這個(gè)方法的返回類型

if(this.method.returnsVoid() && this.method.hasResultHandler()) {

this.executeWithResultHandler(sqlSession, args);

result = null;

} else if(this.method.returnsMany()) {

//我們是查詢列表,此方法執(zhí)行

result = this.executeForMany(sqlSession, args);

} else if(this.method.returnsMap()) {

result = this.executeForMap(sqlSession, args);

} else {

param = this.method.convertArgsToSqlCommandParam(args);

result = sqlSession.selectOne(this.command.getName(), param);

}

} else {

if(SqlCommandType.FLUSH != this.command.getType()) {

throw new BindingException(“Unknown execution method for: ” + this.command.getName());

}

result = sqlSession.flushStatements();

}

if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {

throw new BindingException(“Mapper method ‘” + this.command.getName() + “ attempted to return null from a method with a primitive return type (” + this.method.getReturnType() + “)。”);

} else {

return result;

}

}

private

//將param做處理 自動(dòng)處理為param1,param2.。

Object param = this.method.convertArgsToSqlCommandParam(args);

List result;

if(this.method.hasRowBounds()) {

RowBounds rowBounds = this.method.extractRowBounds(args);

//調(diào)用該對(duì)象的DefaultSqlSession的selectList方法

result = sqlSession.selectList(this.command.getName(), param, rowBounds);

} else {

result = sqlSession.selectList(this.command.getName(), param);

}

return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result;

}

//處理參數(shù)方法

public Object convertArgsToSqlCommandParam(Object[] args) {

int paramCount = this.params.size();

if(args != null && paramCount != 0) {

if(!this.hasNamedParameters && paramCount == 1) {

return args[((Integer)this.params.keySet().iterator().next()).intValue()];

} else {

Map

int i = 0;

for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) {

Entry

param.put(entry.getValue(), args[((Integer)entry.getKey()).intValue()]);

String genericParamName = “param” + String.valueOf(i + 1);

if(!param.containsKey(genericParamName)) {

param.put(genericParamName, args[((Integer)entry.getKey()).intValue()]);

}

}

return param;

}

} else {

return null;

}

}

調(diào)用DefaultSqlSession的selectList的方法

public

List var5;

try {

//獲取MappedStatement對(duì)象

MappedStatement ms = this.configuration.getMappedStatement(statement);

//調(diào)用cachingExecutor執(zhí)行器的方法

var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

} catch (Exception var9) {

throw ExceptionFactory.wrapException(“Error querying database. Cause: ” + var9, var9);

} finally {

ErrorContext.instance().reset();

}

return var5;

}

//CachingExector的query方法

public

//

BoundSql boundSql = ms.getBoundSql(parameterObject);

CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);

//調(diào)用下2代碼

return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

//2代碼

public

Cache cache = ms.getCache();

if(cache != null) {

this.flushCacheIfRequired(ms);

if(ms.isUseCache() && resultHandler == null) {

this.ensureNoOutParams(ms, parameterObject, boundSql);

List

if(list == null) {

//這里是調(diào)用Executor里的query方法 如果開(kāi)啟了緩存這掉CachingExecutor的 如果沒(méi)有則是調(diào)用BaseExecutor的

list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

this.tcm.putObject(cache, key, list);

}

return list;

}

}

return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

BaseExecutor的query方法

public

ErrorContext.instance().resource(ms.getResource()).activity(“executing a query”).object(ms.getId());

if(this.closed) {

throw new ExecutorException(“Executor was closed.”);

} else {

if(this.queryStack == 0 && ms.isFlushCacheRequired()) {

this.clearLocalCache();

}

List list;

try {

++this.queryStack;

list = resultHandler == null?(List)this.localCache.getObject(key):null;

if(list != null) {

this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);

} else {

//如果緩存中沒(méi)有就從數(shù)據(jù)庫(kù)中查詢

list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

}

} finally {

--this.queryStack;

}

if(this.queryStack == 0) {

Iterator i$ = this.deferredLoads.iterator();

while(i$.hasNext()) {

BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)i$.next();

deferredLoad.load();

}

this.deferredLoads.clear();

if(this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {

this.clearLocalCache();

}

}

return list;

}

}

//從數(shù)據(jù)庫(kù)中查詢

private

//放入緩存

this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

List list;

try {

//此處是調(diào)用子Executor的方法,ExecutorType默認(rèn)是使用的SimpleExecutor

list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);

} finally {

this.localCache.removeObject(key);

}

this.localCache.putObject(key, list);

if(ms.getStatementType() == StatementType.CALLABLE) {

this.localOutputParameterCache.putObject(key, parameter);

}

return list;

}

SimpleExecutor的doQuery方法

public

Statement stmt = null;

List var9;

try {

Configuration configuration = ms.getConfiguration();

//創(chuàng)建StateMentHandler處理器

StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

//調(diào)用下3的方法

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

//調(diào)用no4的方法

var9 = handler.query(stmt, resultHandler);

} finally {

this.closeStatement(stmt);

}

return var9;

}

//下3方法

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

Connection connection = this.getConnection(statementLog);

Statement stmt = handler.prepare(connection);

//SatementHanlder 采用PreparedStatementHandler來(lái)實(shí)現(xiàn)此方法,而PreparedStatementHandler調(diào)用的是父接口ParameterHandler的方法

handler.parameterize(stmt);

return stmt;

}

ParameterHandler參數(shù)處理器的方法

public interface ParameterHandler {

Object getParameterObject();

//此方法是用DefaultParameterHandler實(shí)現(xiàn)的

void setParameters(PreparedStatement var1) throws SQLException;

}

DefaultParameterHandler默認(rèn)參數(shù)處理器的方法

public void setParameters(PreparedStatement ps) {

ErrorContext.instance().activity(“setting parameters”).object(this.mappedStatement.getParameterMap().getId());

List

if(parameterMappings != null) {

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

ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);

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

String propertyName = parameterMapping.getProperty();

Object value;

if(this.boundSql.hasAdditionalParameter(propertyName)) {

value = this.boundSql.getAdditionalParameter(propertyName);

} else if(this.parameterObject == null) {

value = null;

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

value = this.parameterObject;

} else {

MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);

value = metaObject.getValue(propertyName);

}

//這里用調(diào)用 TypeHandler類型映射處理器來(lái)映射

TypeHandler typeHandler = parameterMapping.getTypeHandler();

JdbcType jdbcType = parameterMapping.getJdbcType();

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

jdbcType = this.configuration.getJdbcTypeForNull();

}

try {

//類型處理器設(shè)置參數(shù)映射

typeHandler.setParameter(ps, i + 1, value, jdbcType);

} catch (TypeException var10) {

throw new TypeException(“Could not set parameters for mapping: ” + parameterMapping + “。 Cause: ” + var10, var10);

} catch (SQLException var11) {

throw new TypeException(“Could not set parameters for mapping: ” + parameterMapping + “。 Cause: ” + var11, var11);

}

}

}

}

}

no4的方法

public

//此處調(diào)用原生sql的處理器

PreparedStatement ps = (PreparedStatement)statement;

//發(fā)出原生sql命令

ps.execute();

//采用ResultHandler結(jié)果處理器對(duì)結(jié)果集封裝

return this.resultSetHandler.handleResultSets(ps);

}12345678

ResultHandler代碼

public interface ResultSetHandler {

//此處調(diào)用的是DefaultResultSetHandler的方法

void handleOutputParameters(CallableStatement var1) throws SQLException;

}

1234567

DefaultResultSetHandler的方法

public List

ErrorContext.instance().activity(“handling results”).object(this.mappedStatement.getId());

List

int resultSetCount = 0;

ResultSetWrapper rsw = this.getFirstResultSet(stmt);

List

int resultMapCount = resultMaps.size();

this.validateResultMapsCount(rsw, resultMapCount);

while(rsw != null && resultMapCount 》 resultSetCount) {

ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);

this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);

rsw = this.getNextResultSet(stmt);

this.cleanUpAfterHandlingResultSet();

++resultSetCount;

}

String[] resultSets = this.mappedStatement.getResulSets();

if(resultSets != null) {

while(rsw != null && resultSetCount < resultSets.length) {

ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);

if(parentMapping != null) {

String nestedResultMapId = parentMapping.getNestedResultMapId();

ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);

this.handleResultSet(rsw, resultMap, (List)null, parentMapping);

}

rsw = this.getNextResultSet(stmt);

this.cleanUpAfterHandlingResultSet();

++resultSetCount;

}

}

return this.collapseSingleResultList(multipleResults);

}

//處理結(jié)果集

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List

try {

if(parentMapping != null) {

this.handleRowValues(rsw, resultMap, (ResultHandler)null, RowBounds.DEFAULT, parentMapping);

} else if(this.resultHandler == null) {

DefaultResultHandler defaultResultHandler = new DefaultResultHandler(this.objectFactory);

this.handleRowValues(rsw, resultMap, defaultResultHandler, this.rowBounds, (ResultMapping)null);

multipleResults.add(defaultResultHandler.getResultList());

} else {

this.handleRowValues(rsw, resultMap, this.resultHandler, this.rowBounds, (ResultMapping)null);

}

} finally {

this.closeResultSet(rsw.getResultSet());

}

}

private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?》 resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {

if(resultMap.hasNestedResultMaps()) {

this.ensureNoRowBounds();

this.checkResultHandler();

this.handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);

} else {

this.handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);

}

}

private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?》 resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {

DefaultResultContext

this.skipRows(rsw.getResultSet(), rowBounds);

Object rowValue = null;

while(this.shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {

ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, (String)null);

CacheKey rowKey = this.createRowKey(discriminatedResultMap, rsw, (String)null);

Object partialObject = this.nestedResultObjects.get(rowKey);

if(this.mappedStatement.isResultOrdered()) {

if(partialObject == null && rowValue != null) {

this.nestedResultObjects.clear();

this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());

}

//獲取行的值

rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);

} else {

rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);

if(partialObject == null) {

this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());

}

}

}

if(rowValue != null && this.mappedStatement.isResultOrdered() && this.shouldProcessMoreRows(resultContext, rowBounds)) {

this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());

}

}

String resultMapId = resultMap.getId();

Object resultObject = partialObject;

if(partialObject != null) {

MetaObject metaObject = this.configuration.newMetaObject(partialObject);

this.putAncestor(partialObject, resultMapId, columnPrefix);

this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);

this.ancestorObjects.remove(resultMapId);

} else {

ResultLoaderMap lazyLoader = new ResultLoaderMap();

resultObject = this.createResultObject(rsw, resultMap, lazyLoader, columnPrefix);

if(resultObject != null && !this.typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {

MetaObject metaObject = this.configuration.newMetaObject(resultObject);

boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();

if(this.shouldApplyAutomaticMappings(resultMap, true)) {

foundValues = this.applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;

}

foundValues = this.applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;

this.putAncestor(resultObject, resultMapId, columnPrefix);

foundValues = this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;

this.ancestorObjects.remove(resultMapId);

foundValues = lazyLoader.size() 》 0 || foundValues;

resultObject = foundValues?resultObject:null;

}

if(combinedKey != CacheKey.NULL_CACHE_KEY) {

this.nestedResultObjects.put(combinedKey, resultObject);

}

}

return resultObject;

}

private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {

return resultMap.getAutoMapping() != null?resultMap.getAutoMapping().booleanValue():(isNested?AutoMappingBehavior.FULL == this.configuration.getAutoMappingBehavior():AutoMappingBehavior.NONE != this.configuration.getAutoMappingBehavior());

}

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {

List

boolean foundValues = false;

if(autoMapping.size() 》 0) {

Iterator i$ = autoMapping.iterator();

while(true) {

//這里使用了內(nèi)部類對(duì)參數(shù)和結(jié)果集進(jìn)行映射

DefaultResultSetHandler.UnMappedColumAutoMapping mapping;

Object value;

do {

if(!i$.hasNext()) {

return foundValues;

}

mapping = (DefaultResultSetHandler.UnMappedColumAutoMapping)i$.next();

value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);

} while(value == null && !this.configuration.isCallSettersOnNulls());

if(value != null || !mapping.primitive) {

metaObject.setValue(mapping.property, value);

}

foundValues = true;

}

} else {

return foundValues;

}

}

private static class UnMappedColumAutoMapping {

private final String column;

private final String property;

private final TypeHandler<?》 typeHandler;

private final boolean primitive;

//此處才類型器對(duì)結(jié)果進(jìn)行映射

public UnMappedColumAutoMapping(String column, String property, TypeHandler<?》 typeHandler, boolean primitive) {

this.column = column;

this.property = property;

this.typeHandler = typeHandler;

this.primitive = primitive;

}

}

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • mybatis
    +關(guān)注

    關(guān)注

    0

    文章

    64

    瀏覽量

    6896
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    一文了解MyBatis的查詢?cè)?/a>

    本文通過(guò)MyBatis一個(gè)低版本的bug(3.4.5之前的版本)入手,分析MyBatis的一次完整的查詢流程,從配置文件的解析到一個(gè)查詢的完整執(zhí)行過(guò)程詳細(xì)解讀MyBatis的一次查詢流程,通過(guò)本文
    的頭像 發(fā)表于 10-10 11:42 ?1686次閱讀

    Mybatis自動(dòng)生成增刪改查代碼

    使用 mybatis generator 自動(dòng)生成代碼,實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪改查。 1 配置Mybatis插件 在pom文件添加依賴: pluginsplugin
    的頭像 發(fā)表于 01-13 15:43 ?1344次閱讀
    <b class='flag-5'>Mybatis</b>自動(dòng)生成增刪改查代碼

    Mybatis的內(nèi)部設(shè)計(jì)介紹

    Mybatis源碼分析-整體設(shè)計(jì)(一)
    發(fā)表于 06-06 09:43

    基于SpringBoot mybatis方式的增刪改查實(shí)現(xiàn)

    SpringBoot mybatis方式實(shí)現(xiàn)增刪改查
    發(fā)表于 06-18 16:56

    MyBatis的整合

    SpringBoot-15-之整合MyBatis-注解篇+分頁(yè)
    發(fā)表于 10-28 08:09

    Mybatis是什么

    Mybatis第一講
    發(fā)表于 06-04 15:33

    SSM框架在Web應(yīng)用開(kāi)發(fā)中的設(shè)計(jì)與實(shí)現(xiàn) pdf下載

    表現(xiàn)層的功能,比如響應(yīng)請(qǐng)求。Spring 框架主要起到容器的功能,整合了 SpringMVC 和 Mybatis實(shí)現(xiàn)層 與層之間的
    發(fā)表于 01-29 09:47 ?2次下載

    mybatis快速入門

    本文詳細(xì)介紹了mybatis相關(guān)知識(shí),以及mybatis快速入門步驟詳解。
    的頭像 發(fā)表于 02-24 09:41 ?3807次閱讀
    <b class='flag-5'>mybatis</b>快速入門

    easy-mybatis Mybatis的增強(qiáng)框架

    ./oschina_soft/gitee-easy-mybatis.zip
    發(fā)表于 06-14 09:45 ?1次下載
    easy-<b class='flag-5'>mybatis</b> <b class='flag-5'>Mybatis</b>的增強(qiáng)框架

    Fluent Mybatis、原生MybatisMybatis Plus對(duì)比

    使用fluent mybatis可以不用寫具體的xml文件,通過(guò)java api可以構(gòu)造出比較復(fù)雜的業(yè)務(wù)sql語(yǔ)句,做到代碼邏輯和sql邏輯的合一。不再需要在Dao中組裝查詢或更新操作,在xml或
    的頭像 發(fā)表于 09-15 15:41 ?1657次閱讀

    MyBatis-Plus為什么不支持聯(lián)表

    `的所有功能`MyBatis Plus Join`同樣擁有;框架的使用方式和`MyBatis Plus`一樣簡(jiǎn)單,幾行代碼就能實(shí)現(xiàn)聯(lián)表查詢的功能
    的頭像 發(fā)表于 02-28 15:19 ?3035次閱讀
    <b class='flag-5'>MyBatis</b>-Plus為什么不支持聯(lián)表

    MyBatis、JDBC等做大數(shù)據(jù)量數(shù)據(jù)插入的案例和結(jié)果

    30萬(wàn)條數(shù)據(jù)插入插入數(shù)據(jù)庫(kù)驗(yàn)證 實(shí)體類、mapper和配置文件定義 不分批次直接梭哈 循環(huán)逐條插入 MyBatis實(shí)現(xiàn)插入30萬(wàn)條數(shù)據(jù) JDBC實(shí)現(xiàn)插入30萬(wàn)條數(shù)據(jù) 總結(jié) ? 本文主要講述通過(guò)
    的頭像 發(fā)表于 05-22 11:23 ?1298次閱讀
    <b class='flag-5'>MyBatis</b>、JDBC等做大數(shù)據(jù)量數(shù)據(jù)插入的案例和結(jié)果

    SpringBoot+Mybatis如何實(shí)現(xiàn)流式查詢?

    使用mybatis作為持久層的框架時(shí),通過(guò)mybatis執(zhí)行查詢數(shù)據(jù)的請(qǐng)求執(zhí)行成功后,mybatis返回的結(jié)果集不是一個(gè)集合或?qū)ο螅且粋€(gè)迭代器,可以通過(guò)遍歷迭代器來(lái)取出結(jié)果集
    的頭像 發(fā)表于 06-12 09:57 ?1495次閱讀

    mybatis的dao能重載嗎

    不同需求的數(shù)據(jù)操作。 重載是指在同一個(gè)類中定義了多個(gè)方法,它們具有相同的名稱但具有不同的參數(shù)。重載允許使用相同的方法名來(lái)處理不同類型和數(shù)量的參數(shù),以提供更加靈活的操作。 在MyBatis的DAO中,我們可以通過(guò)重載方法來(lái)實(shí)現(xiàn)不同類型和數(shù)量的參數(shù)。例如,可以定義一個(gè)根
    的頭像 發(fā)表于 12-03 11:51 ?1621次閱讀

    mybatis接口動(dòng)態(tài)代理原理

    MyBatis是一款輕量級(jí)的Java持久化框架,它通過(guò)XML或注解配置的方式,將數(shù)據(jù)庫(kù)操作與SQL語(yǔ)句解耦,提供了一種簡(jiǎn)單、靈活的數(shù)據(jù)訪問(wèn)方式。在MyBatis中,使用動(dòng)態(tài)代理技術(shù)來(lái)實(shí)現(xiàn)接口的代理
    的頭像 發(fā)表于 12-03 11:52 ?1224次閱讀
    主站蜘蛛池模板: 夜色福利视频 | 成年女人色费视频免费 | 天天干b | 免费高清一级欧美片在线观看 | 玖玖草在线观看 | 5x视频在线观看 | 成人区精品一区二区毛片不卡 | 直接黄91麻豆网站 | 欧美一级精品高清在线观看 | 最新色网站 | 色3344| 69久久夜色精品国产69小说 | 国产黄大片在线观看 | 亚洲日本中文字幕天天更新 | 久久精品视频99精品视频150 | www.xxx日本人 | 国产高清视频免费最新在线 | 性欧美f| 国产免费一级高清淫日本片 | 手机在线看福利 | 开心激情五月婷婷 | 亚洲男人的天堂久久香蕉 | 成人a毛片视频免费看 | 精品国产综合区久久久久99 | 伊人婷婷色香五月综合缴激情 | 中文一区在线 | 在线观看精品视频看看播放 | 国产紧缚jvid | 日本一本视频 | 欧美乱淫| 伊人成伊人成综合网2222 | 国产精品伦子一区二区三区 | 三级网站在线播放 | 色天使久久综合给合久久97色 | 亚洲欧美综合一区二区三区四区 | 1024你懂的在线观看 | 久青草视频在线 | 久久婷婷激情综合色综合也去 | 免费在线h视频 | 99热最新在线 | 色多多福利 |