成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

mybatis模仿1之我先看看

tylin / 2707人閱讀

摘要:通過(guò)工廠獲得對(duì)象。咱直接看,這個(gè)命名明顯告訴玩家,就在前面了。是個(gè)抽象方法,我們得去看實(shí)現(xiàn)??吹较肟吹臇|西了,之后將結(jié)果交給處理。執(zhí)行完操作之后,將結(jié)果交給。

用了挺久的mybatis,但一直停留在用的層面上,覺(jué)得不行的呀,得走出舒適區(qū)。
所以想自己看看mybatis的實(shí)現(xiàn),然后模仿著寫(xiě)一個(gè),哈哈,當(dāng)然一開(kāi)始不會(huì)要求完成度很高。
這一篇就先看下mybatis奧秘。

這里參考的mybatis源碼版本是3.4.5。

首先,先寫(xiě)一個(gè)mybatis簡(jiǎn)單使用的例子。

// 使用
public static void main(String[] args) throws IOException {
    
    //根據(jù)配置文件創(chuàng)建一個(gè)SqlSessionFactory對(duì)象
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory 
        = new SqlSessionFactoryBuilder().build(inputStream);
    
    // 獲取sqlSession對(duì)象
    SqlSession session = sqlSessionFactory.openSession();
    
    try{
        
        // 獲取接口的實(shí)現(xiàn)類實(shí)例
        IUserMapper mapper = session.getMapper(IUserMapper.class);
        
        // 調(diào)用方法
        User user = mapper.findById(1);
        System.out.println(user.getName());
        
    }finally{
        session.close();
    }
}            

回憶一下,使用Mybatis的步驟就是

寫(xiě)配置文件,配置連接數(shù)據(jù)庫(kù)的參數(shù),mybatis的參數(shù)。

定義接口,并且通過(guò)注解或者xml文件的形式提供SQL語(yǔ)句。之后要在配置文件中注冊(cè)這個(gè)接口。

創(chuàng)建SqlSessionFactory,傳入配置文件。通過(guò)工廠獲得SqlSession對(duì)象。

通過(guò)SqlSession對(duì)象獲取自定義的接口的實(shí)例,然后就是調(diào)用接口的方法。

整個(gè)過(guò)程中,玩家就只參與了配置參數(shù),還有提供SQL這兩步。所以這兩步就是看mybatis怎么操作的入口,是進(jìn)入mybatis地下城的大門(mén)。
配置參數(shù)這部分,使用框架時(shí)基本都有這個(gè)操作,比較常見(jiàn)。所以算是個(gè)分支劇情,而提供SQL算是mybatis的主線劇情,這里先通關(guān)主線劇情。

劇情1 之 發(fā)生了什么
IUserMapper mapper = session.getMapper(IUserMapper.class);
User user = mapper.findById(1);

可以看到,在使用時(shí),我們獲取到了我們的接口的一個(gè)實(shí)現(xiàn)類實(shí)例,
燃鵝,我們沒(méi)有寫(xiě)這個(gè)接口的實(shí)現(xiàn)的呀。所以我覺(jué)得是魔法的原因,在這里要打個(gè)斷點(diǎn)。

在getMapper的方法上斷點(diǎn),我們進(jìn)入了DefaultSqlSession.getMapper(Class),
所以默認(rèn)我們從SqlSessionFactory拿到的是一個(gè)DefaultSqlSession的實(shí)例。

/*
通過(guò)configuration的getMapper方法,傳入我們的接口類型以及SqlSession實(shí)例,返
回一個(gè)泛型。這里也就是我們的IUserMapper接口的實(shí)現(xiàn)類的實(shí)例。*/
@Override
public  T getMapper(Class type) {
    return configuration.getMapper(type, this);
}

再進(jìn)去是Configuration.getMapper(Class, SqlSession)。

/*
這里又從mapperRegistry里拿到對(duì)象,
mapperRegistry是Configuration類的一個(gè)屬性*/
public  T getMapper(Class type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

看一下MapperRegistry的getMapper里邊是什么。
這里看到了令人激動(dòng)的字眼,就是Proxy,
猜測(cè)我們最終拿到的IUserMapper的實(shí)例是個(gè)代理對(duì)象

@SuppressWarnings("unchecked")
public  T getMapper(Class type, SqlSession sqlSession) {
    // 看了下,knownMappers是個(gè)Map對(duì)象,Map, MapperProxyFactory>
    final MapperProxyFactory mapperProxyFactory 
        = (MapperProxyFactory) knownMappers.get(type);
    
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + 
            " is not known to the MapperRegistry.");
    }

    try {
        /*新建一個(gè)實(shí)例,需要進(jìn)去看下*/
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

MapperProxyFactory的newInstance 一探究竟
其實(shí)名字叫xxFactory的肯定是生產(chǎn)xx的,可以猜到返回的是個(gè)MapperProxy

public T newInstance(SqlSession sqlSession) {
    /*這里new了一個(gè)MapperProxy,然后調(diào)用newInstance*/
    final MapperProxy mapperProxy 
        = new MapperProxy(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
}

MapperProxy是個(gè)啥

/* 這個(gè)類實(shí)現(xiàn)了InvocationHandler,動(dòng)態(tài)代理的接口。*/
public class MapperProxy implements InvocationHandler, Serializable 

看看newInstance(mapperProxy)做了啥。
使用Proxy構(gòu)造實(shí)現(xiàn)我們IUserMapper接口的代理類的實(shí)例!

@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}         

消化一下,開(kāi)始的疑問(wèn)是我們沒(méi)有提供IUserMapper的實(shí)現(xiàn),但是通過(guò)SqlSession的getMapper方法能拿到一個(gè)IUserMapper的實(shí)現(xiàn)類的對(duì)象。
謎底就是最終返回了我們接口的一個(gè)代理類的實(shí)例。
而MapperProxy實(shí)現(xiàn)了InvocationHandler接口,在我們構(gòu)造代理對(duì)象時(shí)傳入了MapperProxy對(duì)象,
因此在調(diào)IUserMapper的所有方法時(shí),都會(huì)進(jìn)入到MapperProxy類的invoke方法。
其實(shí)不像上邊那樣操作,通過(guò)直接打印這個(gè)對(duì)象也可以看出來(lái)..

System.out.println(mapper);
System.out.println(Proxy.isProxyClass(mapper.getClass()));
// 打印結(jié)果,貼圖片太丑了,就不貼結(jié)果圖了。
org.apache.ibatis.binding.MapperProxy@e580929
true  

劇情2 之 MapperProxy你干了啥

一般使用動(dòng)態(tài)代理,實(shí)現(xiàn)了InvocationHandler接口的類中都會(huì)持有被代理類的引用,這里也就是MapperProxy。然后在invoke方法里邊先執(zhí)行額外的操作,再調(diào)用被代理類的方法。在MapperProxy這個(gè)類里卻沒(méi)找到被代理類的引用。

public class MapperProxy implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class mapperInterface;
    private final Map methodCache;
    。。。
}

所以穿山甲說(shuō)了什么?
所以當(dāng)我們調(diào)用 IUserMapper 的 findById 時(shí)發(fā)生了什么?
這里就要看下MapperProxy的invoke方法了。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}

首先進(jìn)行一個(gè) if 判斷,邏輯是 如果調(diào)的這個(gè)方法的提供類是Object類,那個(gè)就直接執(zhí)行這個(gè)方法。
這里容易想偏,哪個(gè)類不是Object的子類呀..
其實(shí)應(yīng)該是 如果是Object中的方法,那就直接執(zhí)行。
Object有哪些方法呢?toString這些。調(diào)mapper.toString()時(shí),就直接被執(zhí)行,不走下邊的邏輯了。

if (Object.class.equals(method.getDeclaringClass())) {
    return method.invoke(this, args);
}    

之后是第二個(gè) if,邏輯是,如果這個(gè)方法的權(quán)限修飾符是public并且是由接口提供的,則執(zhí)行invokeDefaultMethod方法。
比如在IUserMapper寫(xiě)了一個(gè)默認(rèn)方法,執(zhí)行這個(gè)方法isDefaultMethod就會(huì)返回true了。
這里我們的方法的提供方是代理類,不是接口,所以返回了false。

else if (isDefaultMethod(method)) {
    return invokeDefaultMethod(proxy, method, args);
}

// isDefaultMethod
private boolean isDefaultMethod(Method method) {
return 
    ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) 
        == Modifier.PUBLIC)
        && 
    method.getDeclaringClass().isInterface();
}

前兩步都是過(guò)濾作用,下邊的才是重點(diǎn)。
可以看到通過(guò) cachedMapperMethod方法 拿到了一個(gè) MapperMethod 對(duì)象。
看名字是從緩存里拿。然后就執(zhí)行MapperMethod的execute方法。

final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);

緩一緩,小結(jié)一下。開(kāi)始的疑問(wèn)是,MapperProxy類里邊竟然沒(méi)有被代理類對(duì)象的引用。
那它想干什么。在invoke方法中我們找到答案。
通過(guò)invoke方法的method參數(shù),拿到了一個(gè)MapperMethod 對(duì)象,
然后執(zhí)行了這個(gè)對(duì)象的execute方法,就沒(méi)了。中間一些常規(guī)的方法就直接執(zhí)行。
所以純粹就是為了進(jìn)入invoke方法,拿到MapperMethod ,至始至終都不存在被代理類。
哇,代理的神奇用法,小本本記起來(lái)。

接著我們看看怎么通過(guò)method參數(shù)拿到MapperMethod
這里就很簡(jiǎn)單了,Map里邊有就直接返回,沒(méi)有就新建。接口的一個(gè)方法就對(duì)應(yīng)一個(gè)MapperMethod。
so easy ~

//cachedMapperMethod
private MapperMethod cachedMapperMethod(Method method) {
    // methodCache 是個(gè)Map
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
        mapperMethod 
            = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
        methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
}

看下MapperMethod的構(gòu)造過(guò)程,發(fā)現(xiàn)傳入了接口信息,方法信息,還有配置信息。
主要工作是初始化 command 還有 method 字段。
command里邊就保存方法的名稱(com.mapper.IUserMapper.findById),還有對(duì)應(yīng)的SQL類型(SELECT)。
method里邊保存了方法的返回類型,是否是集合,是否是游標(biāo)等信息。
看到這里,其實(shí)我一直在忽略Configuration這個(gè)類里邊是什么東西,等要模仿再去看。

public MapperMethod(Class mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);
}

劇情3 之 MapperMethod你跟著干了啥

我們調(diào)用 mapper.findByid, 最終是通過(guò)MapperMethod執(zhí)行execute得到結(jié)果。
所以接下來(lái)要看看execute方法中隱藏了什么秘密。

下邊是execute方法的內(nèi)容

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

    Object result;
    switch (command.getType()) {
        case INSERT: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
        }
        case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
        }
        case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
        }
        case SELECT:
            if (method.returnsVoid() && method.hasResultHandler()) {
                executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (method.returnsMany()) {
                result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
                result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            } else {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(command.getName(), param);
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + command.getName());
    }
    
    if (result == null 
            && method.getReturnType().isPrimitive() 
            && !method.returnsVoid()) {   
        throw new BindingException("Mapper method "" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}

可以看到 INSERT UPDATE 這些熟悉的字眼的了。
通過(guò)MapperMethod里的command的屬性,進(jìn)入不同分支。
這里調(diào)用的是findById,進(jìn)入了SELECT分支,最終執(zhí)行了下邊的語(yǔ)句,第一句是裝配參數(shù),第二句是執(zhí)行查詢。

Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);

看下 sqlSession.selectOne(),里邊調(diào)用了selectList的方法,然后將結(jié)果返回。

@Override
public  T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List list = this.selectList(statement, parameter);
    if (list.size() == 1) {
        return list.get(0);
    } else if (list.size() > 1) {
       throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
        return null;
    }
}

進(jìn)入到selectList瞧瞧,感覺(jué)流程要走完了,都已經(jīng)開(kāi)始select了。
這里又看到了令人激動(dòng)的字眼,statement。感覺(jué)已經(jīng)在靠近JDBC啦。
有個(gè)MappedStatement的對(duì)象需要關(guān)注一下。

@Override
public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        MappedStatement ms = configuration.getMappedStatement(statement);
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

回憶下基本JDBC是怎么用的。

/*
  1 加載對(duì)應(yīng)數(shù)據(jù)庫(kù)驅(qū)動(dòng)
  Class.forName(driverClass);   
  
  2 獲取數(shù)據(jù)庫(kù)連接
  Connection con = DriverManager.getConnection(jdbcUrl, user, password);
  
  3 準(zhǔn)備SQL語(yǔ)句
  String sql = " ... ";
  
  4 執(zhí)行操作
  Statement statement = con.createStatement();
  statement.executeUpdate(sql);
  
  5 釋放資源
  statement.close();
  con.close();*/

MappedStatement是個(gè)什么東西呢,它對(duì)應(yīng)著我們的一條SQL語(yǔ)句。
是通過(guò)MapperMethod的command對(duì)象的name屬性,從configuration里邊拿到的。

拿到MappedStatement之后調(diào)用 executor的query方法,這個(gè)方法是CachingExecutor提供的。
可以看到,這里通過(guò)MappedStatement獲取了我們的SQL,然后生成一個(gè)緩存key,想起我記憶深處的mybatis一級(jí)二級(jí)緩存。
之后返回調(diào)用query方法的結(jié)果。

@Override
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

還是進(jìn)入CachingExecutor的query方法??磥?lái)Executor這樣的類就是真正執(zhí)行數(shù)據(jù)庫(kù)操作的類了。
看到先是從MappedStatement里邊拿緩存,如果是空的,就調(diào)用delegate.query,
delegate是SimpleExecutor類型,顧名思義CachingExecutor委派了SimpleExecutor來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作。

@Override
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
 throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
        flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) {
            ensureNoOutParams(ms, parameterObject, boundSql);
            @SuppressWarnings("unchecked")
            List list = (List) tcm.getObject(cache, key);
            if (list == null) {
                list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                tcm.putObject(cache, key, list); // issue #578 and #116
            }
            return list;
        }
    }
    return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

繼續(xù)看SimpleExecutor里邊的query,看到SimpleExecutor里邊并沒(méi)有query方法,
而是SimpleExecutor繼承了BaseExecutor,query是BaseExecutor類提供的。
第一句斷點(diǎn)進(jìn)去之后,看到的是存起來(lái)的"executing a query",這是出異常時(shí)的堆棧信息。
emm..然后就是很多是否存在緩存是否使用緩存的代碼。
咱直接看queryFromDatabase(),這個(gè)命名明顯告訴玩家,BOSS就在前面了。

@SuppressWarnings("unchecked")
@Override
public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List list;
    try {
        queryStack++;
        list = resultHandler == null ? (List) localCache.getObject(key) : null;
        if (list != null) {
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        } else {
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}

同樣是BaseExecutor 提供的 queryFromDatabase()方法。
首先put進(jìn)去了一個(gè)緩存,key是我們之前的緩存鍵,值是一個(gè)默認(rèn)的值,感覺(jué)是占位的意思。
然后執(zhí)行doQuery方法,看到do開(kāi)頭的方法,就知道不簡(jiǎn)單。doGet doPost
doQuery是個(gè)抽象方法,我們得去SimpleExecutor看實(shí)現(xiàn)。

private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
        localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}

SimpleExecutor.doQuery
來(lái)啦! Statement!而且還有我們熟悉的prepareStatement字眼。哈哈 都是JDBC呀
最后看到是由一個(gè)Handler來(lái)執(zhí)行的,看一看這個(gè)Handler。

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

先是進(jìn)入到了RoutingStatementHandler,然后RoutingStatementHandler委托給了PreparedStatementHandler,下邊是PreparedStatementHandler的query。
看到想看的東西了,ps.execute()
之后將結(jié)果交給resultSetHandler處理。

@Override
public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler. handleResultSets(ps);
}

回顧一下,我們的問(wèn)題是MapperMethod對(duì)象的execute方法做了什么,結(jié)論就是,
我們通過(guò)MapperMethod的command屬性和method屬性,知道了要執(zhí)行的SQL的類型,
這里我們走的是SELECT路線。知道類型之后,交由SqlSession執(zhí)行selectOne方法。
然后又調(diào)用了DefaultSqlSession的selectList方法,DefaultSqlSession表示不想干活,
就交給了勤勞的BaseExecutor,BaseExecutor的里邊有query方法,query方法做一些通用操作,
看一眼有沒(méi)有緩存呀這些。在沒(méi)有或不用緩存的情況下,再去調(diào)doQuery方法,doQuery方法有不同的實(shí)現(xiàn)。
在doQuery以及其要調(diào)用方法里邊使用的就是我們熟悉的JDBC。執(zhí)行完操作之后,將結(jié)果交給resultSetHandler。

總結(jié)

我們使用的是什么?

答:使用的是我們的接口的代理類的實(shí)例。
在構(gòu)造代理類的實(shí)例時(shí),
我們傳入了實(shí)現(xiàn)了InvocationHandler接口的MapperProxy實(shí)例,
當(dāng)代理對(duì)象調(diào)用方法時(shí),會(huì)進(jìn)入MapperProxy的invoke方法。
在invoke方法中通過(guò)Method對(duì)象找MapperMethod,
然后執(zhí)行MapperMethod對(duì)象的execute方法。
在這里,代理的作用是,讓我們知道哪個(gè)接口的哪個(gè)方法被使用了。

MapperProxy 對(duì)應(yīng)了我們的一個(gè)接口,
MapperMethod 對(duì)應(yīng)接口里的一個(gè)方法,
MappedStatement 對(duì)應(yīng)一條SQL

從上邊流程中,總結(jié)各個(gè)類的職責(zé)

MapperProxy: 定義代理對(duì)象調(diào)用方法時(shí)執(zhí)行的動(dòng)作。
即在invoke()里拿到調(diào)用的方法對(duì)應(yīng)的MapperMethod,然后調(diào)用MapperMethod的execute。

MapperMethod: 對(duì)應(yīng)我們接口里的方法,持有SqlCommand(command)和MethodSignature(method),
可以知道方法的全名以及對(duì)應(yīng)的SQL的類型。

MappedStatement: 保存的SQL的信息。

SqlSession: 玩家獲取Mapper的地方。假裝執(zhí)行SQL,實(shí)際交給了Executor。

Executor: 真正執(zhí)行數(shù)據(jù)庫(kù)操作。

大致知道流程是什么樣的,接著就可以模仿著寫(xiě)一寫(xiě)了...
emm...感覺(jué)沒(méi)這么簡(jiǎn)單。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76701.html

相關(guān)文章

  • MongoDB之我是怎么成為Primary節(jié)點(diǎn)的

    摘要:此文已由作者溫正湖授權(quán)網(wǎng)易云社區(qū)發(fā)布。歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。而嚴(yán)格的不會(huì)出現(xiàn)這個(gè)情況。最后安利下,網(wǎng)易蜂巢云服務(wù)已經(jīng)重磅上線,蜂巢由業(yè)界著名的數(shù)據(jù)庫(kù)專家姜承堯親自把關(guān)架構(gòu)設(shè)計(jì),免費(fèi)提供售前技術(shù)支持。 此文已由作者溫正湖授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 Primary(主)是MongoDB復(fù)制集中的最重要的角色,是能夠接...

    microcosm1994 評(píng)論0 收藏0
  • Spring框架之我見(jiàn)(一)——工廠模式

    摘要:相對(duì)于工廠模式,抽象工廠模式生產(chǎn)的對(duì)象更加具體,也更加豐富,但相對(duì)編碼也更加復(fù)雜。具體的抽象工廠模式的實(shí)現(xiàn)大家可以參考菜鳥(niǎo)教程。知道了工廠模式和抽象工廠模式的區(qū)別,請(qǐng)大家使用的時(shí)候應(yīng)該根據(jù)具體的情況進(jìn)行選擇。 大家好,今天給大家分享一些Spring的學(xué)習(xí)心得,在講Spring之前,先和大家分享Spring中核心的設(shè)計(jì)模式。 工廠模式 在聊概念之前我先問(wèn)問(wèn)大家:什么是工廠? 這個(gè)很簡(jiǎn)單,...

    venmos 評(píng)論0 收藏0
  • 教你手寫(xiě)Mybatis框架

    摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫(xiě),讓大家對(duì)的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類,用于解析配置文件加載相關(guān)環(huán)境。配置模塊這里的對(duì)框架的配置使用了簡(jiǎn)單的,主要原因還是簡(jiǎn)單易懂然后節(jié)省時(shí)間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫(xiě)mybatis,讓大家對(duì)mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...

    antyiwei 評(píng)論0 收藏0
  • Spring框架之我見(jiàn)(五)——Spring Boot

    摘要:通過(guò)我們可以更輕松地入門(mén),更簡(jiǎn)單的使用的框架。團(tuán)隊(duì)為了擺脫框架中各類繁復(fù)紛雜的配置,使用約定優(yōu)于配置的思想,在基礎(chǔ)上整合了大量常用的第三方庫(kù)的開(kāi)發(fā)框架。這里還要說(shuō)的一點(diǎn),的出現(xiàn)并不是單純的為了簡(jiǎn)化開(kāi)發(fā),更是為做鋪墊。 說(shuō)完了Spring 我們來(lái)聊聊Spring的進(jìn)階版Spring Boot,如果你還不知道Spring Boot,那希望這篇文章能夠?yàn)槟阒该鞣较颉?Spring Boot ...

    張巨偉 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<