日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

分析mybatis運行原理

瀏覽:116日期:2023-10-19 08:56:04
目錄一、Mybatis基本認識1.1、動態代理1.2、反射二、Configuration對象作用三、映射器結構四、sqlsession執行流程(源碼跟蹤)4.1、Executor4.2、StatementHandler4.3、結果處理器(ResultSetHandler)4.4、總結一、Mybatis基本認識1.1、動態代理 之前我們知道Mapper僅僅是一個接口,而不是一個邏輯實現類。但是在Java中接口是無法執行邏輯的。這里Mybatis就是通過動態代理實現的。關于動態代理我們常用的有Jdk動態代理和cglib動態代理。兩種卻別這里不做贅述。關于CGLIB代理在框架中使用的比較多。 關于動態代理就是所有的請求有一個入口,由這個入口進行分發。在開發領域的一個用途就是【負載均衡】 關于Mybatis的動態代理是使用了兩種的結合。 下面看看JDK和cglib兩種實現

JDK實現首先我們需要提供一個接口 , 這個接口是對我們程序員的一個抽象。 擁有編碼和改BUG的本領

public interface Developer { /** * 編碼 */ void code(); /** * 解決問題 */ void debug();}

關于這兩種本領每個人處理方式不同。這里我們需要一個具體的實例對象

public class JavaDeveloper implements Developer { @Override public void code() {System.out.println('java code'); } @Override public void debug() {System.out.println('java debug'); }}

我們傳統的調用方式是通過java提供的new 機制創造一個JavaDeveloper對象出來。而通過動態代理是通過java.lang.reflect.Proxy對象創建對象調用實際方法的。

通過newProxyInstance方法獲取接口對象的。而這個方法需要三個參數

ClassLoader loader : 通過實際接口實例對象獲取ClassLoader Class<?>[] interfaces : 我們抽象的接口 InvocationHandler h : 對我們接口對象方法的調用。在調用節點我們可以進行我們的業務攔截

JavaDeveloper jDeveloper = new JavaDeveloper();Developer developer = (Developer) Proxy.newProxyInstance(jDeveloper.getClass().getClassLoader(), jDeveloper.getClass().getInterfaces(), (proxy, method, params) -> { if (method.getName().equals('code')) {System.out.println('我是一個特殊的人,code之前先分析問題');return method.invoke(jDeveloper, params); } if (method.getName().equals('debug')) {System.out.println('我沒有bug'); } return null;});developer.code();developer.debug();

CGLIB動態代理

cglib動態代理優點在于他不需要我們提前準備接口。他代理的實際的對象。這對于我們開發來說就很方便了。

public class HelloService { public HelloService() {System.out.println('HelloService構造'); } final public String sayHello(String name) {System.out.println('HelloService:sayOthers>>'+name);return null; } public void sayHello() {System.out.println('HelloService:sayHello'); }}

下面我們只需要實現cglib提供的MethodInterceptor接口,在初始化設置cglib的時候加載這個實例化對象就可以了

public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println('======插入前置通知======');Object object = methodProxy.invokeSuper(o, objects);System.out.println('======插入后者通知======');return object; }}

下面我們就來初始化設置cglib

public static void main(String[] args) { //代理類class文件存入本地磁盤方便我們反編譯查看源代碼 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, '/root/code'); //通過CGLIB動態代理獲取代理對象過程 Enhancer enhancer = new Enhancer(); //設置enhancer對象的父類 enhancer.setSuperclass(HelloService.class); // 設置enhancer的回調對象 enhancer.setCallback(new MyMethodInterceptor()); //創建代理對象 HelloService helloService = (HelloService) enhancer.create(); //通過代理對象調用目標方法 helloService.sayHello();}

仔細看看cglib和spring的aop特別像。針對切點進行切面攔截控制。

總結:

通過對比兩種動態代理我們很容易發現,mybatis就是通過JDK代理實現Mapper調用的。我們Mapper接口實現通過代理到xml中對應的sql執行邏輯

1.2、反射 相信有一定經驗的Java工程師都對反射或多或少有一定了解。其實從思想上看不慣哪種語言都是有反射的機制的。 通過反射我們就擺脫了對象的限制我們調用方法不再需要通過對象調用了。可以通過Class對象獲取方法對象。從而通過invoke方法進行方法的調用了。二、Configuration對象作用

Configuration對象存儲了所有Mybatis的配置。主要初始化一下參數

properties settings typeAliases typeHandler ObjectFactory plugins environment DatabaseIdProvider Mapper映射器三、映射器結構

分析mybatis運行原理

BoundSql提供三個主要的屬性 parameterMappings 、parameterObject、sql parameterObject參數本身。我們可以傳遞java基本類型、POJO、Map或者@Param標注的參數。 當我們傳遞的是java基本類型mybatis會轉換成對應的包裝對象 int -> Integer 如果我們傳遞POJO、Map。就是對象本身 我們傳遞多個參數且沒有@Param指定變量名則parameterObject 類似 {'1':p1,'2':p2,'param1':p1,'param2':p2} 我們傳遞多個參數且@Param指定變量名 則parameterObject類似 {'key1':p1,'key2':p2,'param1':p1,'param2':p2} parameterMapping 是記錄屬性、名稱、表達式、javaType,jdbcType、typeHandler這些信息 sql 屬性就是我們映射器中的一條sql. 正常我們在常見中對sql進行校驗。正常不需要修改sql。四、sqlsession執行流程(源碼跟蹤)

首先我們看看我們平時開發的Mapper接口是如何動態代理的。這就需要提到MapperProxyFactory這個類了。該類中的newInstance方法

protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }

通過上滿代碼及上述對jdk動態代理的表述。我們可以知道mapperProxy是我們代理的重點。MapperProxy是InvocationHandler的實現類。他重寫的invoke方法就是代理對象執行的方法入口。

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

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

通過源碼發現。invoke內部首先判斷對象是否是類 。 通過打斷點發現最終會走到cacheMapperMethod這個方法去創建MapperMethod對象。繼續查看MapperMethod中execute方法我們可以了解到內部實現其實是一個命令行模式開發。通過判斷命令從而執行不同的語句。判斷到具體執行語句然后將參數傳遞給sqlsession進行sql調用并獲取結果。到了sqlsession就和正常jdbc開發sql進行關聯了。sqlsession中Executor、StatementHandler、ParameterHandler、Resulthandler四大天王

4.1、Executor

顧名思義他就是一個執行器。將java提供的sql提交到數據庫。Mybatis提供了三種執行器。

Configuration.class中newExecutor源碼

分析mybatis運行原理

根據uml我們不難看出mybatis中提供了三類執行器分別SimpleExecutor、ReuseExecutor、BatchExecutor

public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 得到configuration 中的environment final Environment environment = configuration.getEnvironment(); // 得到configuration 中的事務工廠 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 獲取執行器 final Executor executor = configuration.newExecutor(tx, execType); // 返回默認的SqlSession return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException('Error opening session. Cause: ' + e, e); } finally { ErrorContext.instance().reset(); } }

通過上述源碼我們知道在sqlsession獲取一個數據庫session對象時我們或根據我們的settings配置加載一個Executor對象。在settings中配置也很簡單

<settings><!--取值范圍 SIMPLE, REUSE, BATCH --><setting name='defaultExecutorType' value='SIMPLE'/></settings>

我們也可以通過java代碼設置

factory.openSession(ExecutorType.BATCH);4.2、StatementHandler

顧名思義,StatementHandler就是專門處理數據庫回話的。這個對象的創建還是在Configuration中管理的。

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

很明顯Mybatis中StatementHandler使用的是RoutingStatementHandler這個class

分析mybatis運行原理

關于StatementHandler和RoutingStatementHandler之間的關系我們通過源碼可以看出這里和Executor一樣都是適配器模式。采用這種模式的好處是方便我們對這些對象進行代理。這里讀者可以猜測一下是使用了哪種動態代理。給點提示 這里使用了接口哦

分析mybatis運行原理分析mybatis運行原理

在查看BaseStatementHandler結構我們會發現和Executor一模一樣。同樣的Mybatis在構造RoutingStatementHandler的時候會根據setting中配置來加載不同的具體子類。這些子類都是繼承了BaseStatementHandler.

前一節我們跟蹤了Executor。 我們知道Mybatis默認的是SimpleExecutor。 StatementHandler我們跟蹤了Mybaits默認的是PrePareStatementHandler。在SimpleExecutor執行查詢的源碼如下

分析mybatis運行原理分析mybatis運行原理

我們發現在executor查詢錢會先讓statementHandler構建一個Statement對象。最終就是StatementHandler中prepare方法。這個方法在抽象類BaseStatmentHandler中已經封裝好了。

分析mybatis運行原理

這個方法的邏輯是初始化statement和設置連接超時等一些輔助作用

然后就是設置一些參數等設置。最后就走到了執行器executor的doquery

分析mybatis運行原理

PrepareStatement在我們jdbc開發時是常見的一個類 。 這個方法執行execute前我們需要設置sql語句,設置參數進行編譯。這一系列步驟就是剛才我們說的流程也是PrepareStatementHandler.prepareStatement幫我們做的事情。那么剩下的我們也很容易想到就是我們對數據結果的封裝。正如代碼所示下馬就是resultSetHandler幫我們做事情了。

4.3、結果處理器(ResultSetHandler)

@Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity('handling results').object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++; } } return collapseSingleResultList(multipleResults); }

這個方法我們可以導出來是結果xml中標簽配置對結果的一個封裝。

4.4、總結

SqlSession在一個查詢開啟的時候會先通過CacheExecutor查詢緩存。擊穿緩存后會通過BaseExector子類的SimpleExecutor創建StatementHandler。PrepareStatementHandler會基于PrepareStament執行數據庫操作。并針對返回結果通過ResultSetHandler返回結果數據

分析mybatis運行原理

以上就是分析mybatis運行原理的詳細內容,更多關于mybatis運行原理的資料請關注好吧啦網其它相關文章!

標簽: Mybatis 數據庫
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品视频3p| 91成人在线网站| 精品一区二区三区亚洲| 国产精品视频一区二区三区| 免费成人在线影院| 免播放器亚洲| 日韩福利视频导航| 欧美亚洲tv| 精品一区二区三区中文字幕在线| 久久精品97| 久久精品一区二区国产| 成人精品国产亚洲| 欧美日韩国产v| 免费欧美一区| 中文字幕av一区二区三区人| 蜜桃一区二区三区在线观看| 日韩高清不卡一区二区| 久久精品一本| 欧美久久精品一级c片| 久久久9色精品国产一区二区三区| 国产高清不卡| 日韩一区精品视频| 国产精品18| 一区三区视频| 91久久精品无嫩草影院| 国产精品成久久久久| 欧美精品九九| 麻豆成人91精品二区三区| 久久久久久黄| 91亚洲精品在看在线观看高清| 国产精品伦理久久久久久| 午夜久久99| 精品久久不卡| 亚洲aⅴ网站| 91偷拍一区二区三区精品| 99热精品在线观看| 久久久久亚洲精品中文字幕| 国产免费成人| 久久只有精品| 中文无码久久精品| 日韩av片子| 青青草伊人久久| 狠狠色综合网| 日韩不卡免费高清视频| 国产精品久久久久久久久久妞妞 | 日韩精品一级中文字幕精品视频免费观看| 亚洲丝袜美腿一区| 婷婷综合社区| 亚洲va中文在线播放免费| 日韩成人精品一区二区三区| 1024精品一区二区三区| 久久精品亚洲| 国产精品亚洲综合久久| 亚洲一区二区日韩| 9国产精品视频| 亚洲一级二级| 香蕉久久99| 亚洲福利精品| 91精品成人| 婷婷六月综合| 亚洲主播在线| 欧美日韩在线二区| 日韩三区免费| 丝袜美腿诱惑一区二区三区| 日韩毛片视频| 亚洲韩日在线| 亚洲激情不卡| 视频一区二区三区在线| 在线亚洲一区| 国产欧美一区二区精品久久久| 91成人福利| 高清精品久久| 不卡在线一区| 美女91精品| 国产欧美激情| 久久久蜜桃一区二区人| 亚洲精品在线观看91| 国产一区91| 欧美精品国产白浆久久久久| 久久女人天堂| 在线亚洲精品| 狂野欧美性猛交xxxx| 久久精品高清| 日韩精品一区二区三区中文| 国产精品免费99久久久| 精品女同一区二区三区在线观看| 激情亚洲影院在线观看| 亚洲一区国产一区| 久久成人福利| 亚洲综合精品| 精品视频国内| 宅男在线一区| 欧美国产极品| 天堂va蜜桃一区二区三区| 欧美激情网址| 亚洲一区二区av| 日韩在线第七页| 国产亚洲一区二区三区不卡| 亚洲高清毛片| 国产福利91精品一区二区| 中文一区一区三区免费在线观 | 国产欧美综合一区二区三区| 久久精品官网| 国产精品美女久久久久久不卡| 午夜国产精品视频免费体验区| 国产精品夜夜夜| 中日韩男男gay无套| 精品午夜视频| 欧美一区91| 免费日韩av片| 免费观看久久av| 91日韩欧美| 韩日一区二区| 美腿丝袜亚洲一区| 日本少妇精品亚洲第一区| 亚洲欧美日韩综合国产aⅴ| 麻豆成人av在线| 国产精品一区二区99| 日韩精品免费视频人成| 在线亚洲免费| 日韩午夜免费| 视频小说一区二区| 色一区二区三区四区| 国产精品视频一区二区三区四蜜臂 | 精品网站999| 91精品国产自产精品男人的天堂| 欧美天堂亚洲电影院在线观看| 成人午夜国产| 久久中文亚洲字幕| 国产精品久久久久av电视剧| 日本在线啊啊| japanese国产精品| 国产亚洲一区在线| 亚洲欧美专区| 国产人成精品一区二区三| 国产精品探花在线观看| 麻豆精品少妇| 中国字幕a在线看韩国电影| 视频在线不卡免费观看| 四季av一区二区凹凸精品| 日本午夜大片a在线观看| 免费一二一二在线视频| 国产精品7m凸凹视频分类| 免费日本视频一区| 亚洲精品一级| 国产一区2区| 亚洲综合另类| 国产精品a级| 精品亚洲美女网站| 蜜臀va亚洲va欧美va天堂| 日本午夜精品视频在线观看| 久久99国产精品视频| 欧美午夜精彩| 欧美日韩一区二区三区四区在线观看| 九九久久国产| 丝袜诱惑制服诱惑色一区在线观看| 91麻豆精品激情在线观看最新| 日韩欧美网址| 欧美日韩亚洲一区在线观看| 国产成人精品一区二区三区免费 | 视频一区日韩精品| 国产精品蜜芽在线观看| 久久一二三区| 国产99在线| 亚洲精品国产精品粉嫩| 亚洲a一区二区三区| 亚洲一区二区三区无吗| 狠狠躁少妇一区二区三区| 亚洲精品一区二区妖精| 捆绑调教美女网站视频一区| 在线国产一区二区| 久久精品国产99国产| 久久婷婷亚洲| 久久av中文| 久久xxxx精品视频| 999国产精品999久久久久久| 亚洲制服欧美另类| 午夜日韩av| 欧产日产国产精品视频| 久久av免费| 亚洲+小说+欧美+激情+另类| 91tv亚洲精品香蕉国产一区| 国产日产精品一区二区三区四区的观看方式 | 国产精品igao视频网网址不卡日韩 | 日韩免费在线| 91一区二区三区四区| 国产精品一级在线观看| 日韩一区二区三免费高清在线观看 | 国产欧美久久一区二区三区| 日韩在线一二三区| 欧美 日韩 国产一区二区在线视频| 久久69成人| 麻豆中文一区二区| 欧美aⅴ一区二区三区视频| 88久久精品| 国产精品久久| 国产一区丝袜| 久久99国产精品视频| 欧美黑人巨大videos精品| 欧美激情视频一区二区三区免费|