1、創(chuàng)建項(xiàng)目maven,方便依賴下載。使用的jar如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<dependencies> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-context</artifactid> <version> 5.0 . 8 .release</version> </dependency> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis-spring</artifactid> <version> 2.0 . 0 </version> </dependency> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis</artifactid> <version> 3.4 . 6 </version> </dependency> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version> 5.1 . 34 </version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-jdbc</artifactid> <version> 5.0 . 8 .release</version> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-core</artifactid> <version> 5.0 . 8 .release</version> </dependency> </dependencies> |
2、創(chuàng)建包c(diǎn)om >config、dao、service、test
3、使用spring創(chuàng)建appconfig文件,創(chuàng)建bean>sqlsessionfactorybean、datasourcebean
1、spring注解@configuration,說明是配置層
2、注冊掃描映射
3、注冊包掃描器
4、創(chuàng)建sqlsessionfactorybean
5、創(chuàng)建數(shù)據(jù)源bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.config; import org.mybatis.spring.sqlsessionfactorybean; import org.mybatis.spring.annotation.mapperscan; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.componentscan; import org.springframework.context.annotation.configuration; import org.springframework.jdbc.datasource.drivermanagerdatasource; import javax.sql.datasource; @configuration @mapperscan ( "com.dao" ) //注解 與xml<mybatis:scan base-package="org.mybatis.spring.sample.mapper" /> //注冊包中遞歸搜索映射器 @componentscan ( "com" ) //注冊bean public class appconfig { @bean @autowired public sqlsessionfactorybean sqlsessionfactorybean(datasource datasource ){ sqlsessionfactorybean sqlsessionfactorybean = new sqlsessionfactorybean(); sqlsessionfactorybean.setdatasource(datasource); return sqlsessionfactorybean; } @bean public datasource getdatasource(){ drivermanagerdatasource datasource = new drivermanagerdatasource(); datasource.setdriverclassname( "com.mysql.jdbc.driver" ); datasource.setusername( "root" ); datasource.setpassword( "110226wjwj" ); datasource.seturl( "jdbc:mysql://localhost:3306/mybatis_wjw?useunicode=true&characterencoding=utf-8&usessl=false" ); return datasource; } } |
4、創(chuàng)建dao接口
1、創(chuàng)建query方法并使用注解@select(mybatis提供,mybatis-spring官網(wǎng)有相關(guān)解釋)
1
2
3
4
5
6
7
8
|
package com.dao; import org.apache.ibatis.annotations.select; import java.util.list; import java.util.map; public interface userdao { @select ( "select * from t_user where tid =3" ) public list<map> query(); } |
5、創(chuàng)建服務(wù)層
1、注解服務(wù)層
2、引入daobean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.service; import com.dao.userdao; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.service; //spring注解中service與component意思差不多,區(qū)別在于component是中立注解,而service是業(yè)務(wù)邏輯層的注解 //@component @service public class userservice { @autowired userdao userdao; public void query(){ system.out.println(userdao.query()); } } |
6、測試
1、創(chuàng)建application
2、創(chuàng)建service
1
2
3
4
5
6
7
8
9
10
11
|
package com.test; import com.config.appconfig; import com.service.userservice; import org.springframework.context.annotation.annotationconfigapplicationcontext; public class maintest { public static void main(string args[]){ annotationconfigapplicationcontext acc = new annotationconfigapplicationcontext(appconfig. class ); userservice us = acc.getbean(userservice. class ); us.query(); } } |
jar包之家:https://mvnrepository.com/artifact
使用spring依賴注入mapper 根據(jù)官網(wǎng)提示需要
<mybatis:scan base-package="org.mybatis.spring.sample.mapper" />==@mapperscan(“需要注入的包”)
mybatis缺點(diǎn):使用xml方式與dao開發(fā)結(jié)合出現(xiàn)嚴(yán)重的臃腫現(xiàn)象,需要維護(hù)很多sql語句。
測試的時(shí)候出現(xiàn)這個(gè)問題。(版本導(dǎo)致,我直接將最新[mybatis-spring]的導(dǎo)入進(jìn)來就沒問題了)
上面的問題解決后有出現(xiàn)這個(gè)問題,此問題出現(xiàn)的原因是java compiler改成8就ok了
測試結(jié)果:
重點(diǎn):
mybatis運(yùn)行原理
我們可以看到,再測試類中用的是userservice對象調(diào)用dao接口中的query,但是mybatis是如何實(shí)現(xiàn)將接口轉(zhuǎn)換成對象的呢? 答案:動(dòng)態(tài)代理 ,我們常用的代理(proxy)一共有兩種:cglib和jdk兩用代理模式
無論哪一種最終都是使用反射機(jī)制進(jìn)行代理。詳情自己查看度娘(哈哈@0@)
mybatis源碼解析
defaultsqlsession下如何實(shí)現(xiàn)返回一條數(shù)據(jù)的:底層調(diào)用的是selectlist方法,對返回的結(jié)果集進(jìn)行數(shù)量判斷如果==1則直接放回,>1直接拋出toomanyresultsexception(感覺很傻,有些妄自菲薄!)
1
2
3
4
5
6
7
8
9
10
|
public <t> t selectone(string statement, object parameter) { list<t> 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 ; } } |
下面我們繼續(xù)看selectlist是如何實(shí)現(xiàn)的
1
2
3
4
5
6
7
8
9
10
11
12
|
public <e> list<e> selectlist(string statement, object parameter, rowbounds rowbounds) { list var5; try { mappedstatement ms = this .configuration.getmappedstatement(statement); 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; } |
我們來看看這個(gè)defaultsqlsession.configuration.getmappedstatement方法具體是什么
結(jié)論:再啟動(dòng)項(xiàng)目的時(shí)候,mybatis會(huì)進(jìn)行初始化,這個(gè)初始化就是將我們的"包+類+方法名"作為key 和 sql語句作為value 的鍵值對形式賦給下面map類型的mappedstatements
protected final map<string, mappedstatement> mappedstatements;
這也是為什么我們使用xml方式一定要將方法名字與id對應(yīng)上才能使用,如果對應(yīng)不上再進(jìn)行id傳值的時(shí)候找不到對應(yīng)的key。
繼續(xù)往下分析:
已發(fā)帖子詢問大神具體是什么原因?qū)е虏贿M(jìn)入124行,等大佬們回答后我將公布結(jié)果。直接看看executor是什么鬼
是一個(gè)接口,https://blog.csdn.net/ykzhen2015/article/details/50315027
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
protected set<beandefinitionholder> doscan(string... basepackages) { assert .notempty(basepackages, "at least one base package must be specified" ); set<beandefinitionholder> beandefinitions = new linkedhashset(); string[] var3 = basepackages; int var4 = basepackages.length; for ( int var5 = 0 ; var5 < var4; ++var5) { string basepackage = var3[var5]; set<beandefinition> candidates = this .findcandidatecomponents(basepackage); iterator var8 = candidates.iterator(); while (var8.hasnext()) { beandefinition candidate = (beandefinition)var8.next(); scopemetadata scopemetadata = this .scopemetadataresolver.resolvescopemetadata(candidate); candidate.setscope(scopemetadata.getscopename()); string beanname = this .beannamegenerator.generatebeanname(candidate, this .registry); if (candidate instanceof abstractbeandefinition) { this .postprocessbeandefinition((abstractbeandefinition)candidate, beanname); } if (candidate instanceof annotatedbeandefinition) { annotationconfigutils.processcommondefinitionannotations((annotatedbeandefinition)candidate); } if ( this .checkcandidate(beanname, candidate)) { beandefinitionholder definitionholder = new beandefinitionholder(candidate, beanname); definitionholder = annotationconfigutils.applyscopedproxymode(scopemetadata, definitionholder, this .registry); beandefinitions.add(definitionholder); this .registerbeandefinition(definitionholder, this .registry); } } } return beandefinitions; } |
關(guān)于mybatis中的executor與一級緩存的關(guān)系:
這里引出一個(gè)經(jīng)典問題,關(guān)于mybatis一級緩存問題,這個(gè)緩存存儲(chǔ)在session中,當(dāng)sql關(guān)閉的時(shí)候就會(huì)自動(dòng)銷毀,涉及到mybatis中的session生命周期問題
為什么mybatis與spring結(jié)合后一級緩存會(huì)失效?以為sqlsession是由sqlsessionfactorybean生成,二這個(gè)sqlsessionfactorybean是由spring管理,也就是此時(shí)的session是由spring進(jìn)行管理的并不是mybatis管理,所以此時(shí)session緩存會(huì)失效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public interface executor { resulthandler no_result_handler = null ; int update(mappedstatement var1, object var2) throws sqlexception; <e> list<e> query(mappedstatement var1, object var2, rowbounds var3, resulthandler var4, cachekey var5, boundsql var6) throws sqlexception; <e> list<e> query(mappedstatement var1, object var2, rowbounds var3, resulthandler var4) throws sqlexception; <e> cursor<e> querycursor(mappedstatement var1, object var2, rowbounds var3) throws sqlexception; list<batchresult> flushstatements() throws sqlexception; void commit( boolean var1) throws sqlexception; void rollback( boolean var1) throws sqlexception; cachekey createcachekey(mappedstatement var1, object var2, rowbounds var3, boundsql var4); boolean iscached(mappedstatement var1, cachekey var2); void clearlocalcache(); void deferload(mappedstatement var1, metaobject var2, string var3, cachekey var4, class <?> var5); transaction gettransaction(); void close( boolean var1); boolean isclosed(); void setexecutorwrapper(executor var1); } |
mybatis-spring依賴中mapperscannerregistrar的作用:registerbeandefinitions方法中的doscan()此方法是將mapper掃描到初始化中。原理就是獲取到項(xiàng)目路徑找到對應(yīng)的classes路徑,獲取了com.dao包名,將獲取的路徑+包名轉(zhuǎn)成文件夾,循環(huán)獲取文件夾下面的文件(userdao.class),然后使用將userdao拿到。此時(shí)包名+類名都拿到后使用class.forname(包名+類名)反射出對象,進(jìn)行bean注冊
總結(jié)運(yùn)行原理:
初始化信息(數(shù)據(jù)庫連接信息,掃描mapper包中的class用于創(chuàng)建bean對象,spring中的類applicationfactory用于創(chuàng)建變對象、mapper中的xml的id與sql放到mapperstatement對象中)
其中對于掃描mapper包中的class路徑+參數(shù)basepackages轉(zhuǎn)成文件夾,然后循環(huán)找到所有的類名,使用.......(請看mapperscannerregistrar引出的doscan方法)
執(zhí)行過程:根據(jù)sqlsessionfactorybean創(chuàng)建出sqlsession,調(diào)用selectlist方法,之后根據(jù)參數(shù)(namespacename+id)作為key找到mapperstatement對象中存儲(chǔ)的value獲取到sql語句,再有executor(mybatis默認(rèn)使用 cacheexecutor)執(zhí)行sql語句查詢出結(jié)果集
原文鏈接:https://www.cnblogs.com/gnwzj/p/10680940.html