激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - mybatis查詢語句揭秘之封裝數(shù)據(jù)

mybatis查詢語句揭秘之封裝數(shù)據(jù)

2021-07-29 11:31不懂是非 Java教程

這篇文章主要給大家介紹了關(guān)于mybatis查詢語句揭秘之封裝數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

一、前言

繼上一篇mybatis查詢語句的背后,這一篇主要圍繞著mybatis查詢的后期操作,即跟數(shù)據(jù)庫交互的時候。由于本人也是一邊學(xué)習(xí)源碼一邊記錄,內(nèi)容難免有錯誤或不足之處,還望諸位指正,本文只可當(dāng)參考作用。謹(jǐn)記!

二、分析

繼上一篇博文的查詢例子,mybatis在最后的查詢最終會走simpleexecutor類的doquery方法,

?
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
@override
 public <e> list<e> doquery(mappedstatement ms, object parameter, rowbounds rowbounds, resulthandler resulthandler, boundsql boundsql) throws sqlexception {
 statement stmt = null;
 try {
 configuration configuration = ms.getconfiguration();
 // 這里也就是采用了策略模式(個人感覺有點(diǎn)像),實(shí)際的statementhandler為routingstatementhandler
 statementhandler handler = configuration.newstatementhandler(wrapper, ms, parameter, rowbounds, resulthandler, boundsql);
 stmt = preparestatement(handler, ms.getstatementlog());
 // 雖然是執(zhí)行的routingstatementhandler.query,但返回結(jié)果的還是preparedstatementhandler處理
 return handler.query(stmt, resulthandler);
 } finally {
 closestatement(stmt);
 }
 }
 
private statement preparestatement(statementhandler handler, log statementlog) throws sqlexception {
 statement stmt;
 // 使用了代理模式,也可以理解為對connection進(jìn)行了一層包裝,這里的作用就是加了log處理
 connection connection = getconnection(statementlog);
 //進(jìn)行預(yù)編譯,即類似jdbc的 sql,如 select * from user where id=?
 stmt = handler.prepare(connection, transaction.gettimeout());
 // 對執(zhí)行查詢的sql進(jìn)行參數(shù)設(shè)置
 handler.parameterize(stmt);
 return stmt;
 }

關(guān)于 handler.prepare的作用這里簡單介紹下,不做代碼分析。

會設(shè)置fetchsize,作用就是一次性從數(shù)據(jù)庫抓取數(shù)據(jù),好像默認(rèn)值是10條,如果每次只抓取一條,則進(jìn)行rs.next的時候,會再次查庫。

如果是insert操作,并且數(shù)據(jù)庫主鍵自增且還設(shè)置了可以返回主鍵,則會還做獲取主鍵的操作。

先從設(shè)置參數(shù)說起,也就是handler.parameterize。先看下源碼,具體位置在defaultparameterhandler類里面

?
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
33
34
35
36
37
38
39
40
41
42
43
@override
 public void setparameters(preparedstatement ps) {
 errorcontext.instance().activity("setting parameters").object(mappedstatement.getparametermap().getid());
 // 獲取配置文件里面的sql參數(shù)信息,如sql為select * from user where id=#{userid,jdbctype=integer}
 // parametermapping 記錄了參數(shù)名也就是userid,還有記錄了對應(yīng)的jdbc類型,還有對應(yīng)的javatype等等,具體可以debug看下
 list<parametermapping> parametermappings = boundsql.getparametermappings();
 if (parametermappings != null) {
 for (int i = 0; i < parametermappings.size(); i++) {
 parametermapping parametermapping = parametermappings.get(i);
 if (parametermapping.getmode() != parametermode.out) {
  object value;
  string propertyname = parametermapping.getproperty();
  // 如果為true,那么sql參數(shù)中有類似 user.name 格式
  if (boundsql.hasadditionalparameter(propertyname)) { // issue #448 ask first for additional params
  value = boundsql.getadditionalparameter(propertyname);
  } else if (parameterobject == null) {
  value = null;
  } else if (typehandlerregistry.hastypehandler(parameterobject.getclass())) {
  value = parameterobject;
  } else {
  // metaobject 類似一個工具類,它里面有一個反射工廠,可以專門解析一個類的信息,如字段的setter/getter/屬性信息,這里不做多余介紹
  // 1、下面詳細(xì)介紹
  metaobject metaobject = configuration.newmetaobject(parameterobject);
  value = metaobject.getvalue(propertyname);// 取值
  }
  // 獲取對應(yīng)的typehandler,一般情況不設(shè)置的話,基本都是objecttypehandler
  typehandler typehandler = parametermapping.gettypehandler();
  jdbctype jdbctype = parametermapping.getjdbctype();
  if (value == null && jdbctype == null) {
  jdbctype = configuration.getjdbctypefornull();
  }
  try {
  // 進(jìn)行設(shè)值
  typehandler.setparameter(ps, i + 1, value, jdbctype);
  } catch (typeexception e) {
  throw new typeexception("could not set parameters for mapping: " + parametermapping + ". cause: " + e, e);
  } catch (sqlexception e) {
  throw new typeexception("could not set parameters for mapping: " + parametermapping + ". cause: " + e, e);
  }
 }
 }
 }
 }

對于上述代碼中的一部分這里負(fù)責(zé)將parameterobject的里面的值整出來(也就是傳入的參數(shù)),如果參數(shù)是map結(jié)構(gòu),就從map里面取值,如果不是,如單個非javabean參數(shù),則直接取值,如果是單個javabean,則通過metaobject類轉(zhuǎn)換成一個beanwrapper,進(jìn)行取值

這段代碼也就負(fù)責(zé)對預(yù)編譯后的sql設(shè)置參數(shù),這里邏輯主要是圍繞以下步驟進(jìn)行得,

獲取參數(shù)名,獲取參數(shù)值,獲取參數(shù)類型,然后做進(jìn)行設(shè)值操作

?
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
 * mybatis數(shù)據(jù)處理有單結(jié)果集和多結(jié)果集處理,一般多結(jié)果集出現(xiàn)存儲過程中,如果存儲過程中寫了兩條select語句,如
 * select * from user , select * from classes 這種情況這里不做介紹,因?yàn)楸救擞玫牟欢啵斫獾囊膊皇呛芡笍亍?/code>
 * 這里不多做介紹,這里只針對簡單映射做一個大概介紹
 *
 */
public list<object> handleresultsets(statement stmt) throws sqlexception {
 errorcontext.instance().activity("handling results").object(mappedstatement.getid());
 // 保存查詢結(jié)果
 final list<object> multipleresults = new arraylist<>();
 
 int resultsetcount = 0;
 // 獲取第一條數(shù)據(jù)
 resultsetwrapper rsw = getfirstresultset(stmt);
 // 如果不是多結(jié)果集映射,一般resultmaps的大小為1
 // resultmap中存儲的有類的字段屬性,數(shù)據(jù)庫字段名稱等信息
 list<resultmap> resultmaps = mappedstatement.getresultmaps();
 int resultmapcount = resultmaps.size();
 // 校驗(yàn)數(shù)據(jù)的正確性
 validateresultmapscount(rsw, resultmapcount);
 while (rsw != null && resultmapcount > resultsetcount) {
 resultmap resultmap = resultmaps.get(resultsetcount);
 // 處理結(jié)果集映射
 handleresultset(rsw, resultmap, multipleresults, null);
 rsw = getnextresultset(stmt);
 cleanupafterhandlingresultset();
 resultsetcount++;
 }
 // 處理slect 標(biāo)簽的resultsets屬性,多個用逗號隔開,個人幾乎沒用過,略過
 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);
 }

以上代碼就是為結(jié)果映射做一個鋪墊,重點(diǎn)是在hanleresultset方法里,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void handleresultset(resultsetwrapper rsw, resultmap resultmap, list<object> multipleresults, resultmapping parentmapping) throws sqlexception {
 try {// 針對簡單映射,parentmapping是為null的
 if (parentmapping != null) {
 handlerowvalues(rsw, resultmap, null, rowbounds.default, parentmapping);
 } else {
 // 默認(rèn)使用defaultresulthandler,如需使用自定義的,則可在傳參加入resulthandler接口實(shí)現(xiàn)類
 if (resulthandler == null) {
  defaultresulthandler defaultresulthandler = new defaultresulthandler(objectfactory);
  // 處理結(jié)果,結(jié)果存在resulthandler里
  handlerowvalues(rsw, resultmap, defaultresulthandler, rowbounds, null);
  multipleresults.add(defaultresulthandler.getresultlist());
 } else {
  handlerowvalues(rsw, resultmap, resulthandler, rowbounds, null);
 }
 }
 } finally {
 // issue #228 (close resultsets)
 closeresultset(rsw.getresultset());
 }
 }
?
1
2
3
4
5
6
7
8
9
10
public void handlerowvalues(resultsetwrapper rsw, resultmap resultmap, resulthandler<?> resulthandler, rowbounds rowbounds, resultmapping parentmapping) throws sqlexception {
 // 處理有嵌套映射的情況
 if (resultmap.hasnestedresultmaps()) {
 ensurenorowbounds();
 checkresulthandler();
 handlerowvaluesfornestedresultmap(rsw, resultmap, resulthandler, rowbounds, parentmapping);
 } else {//沒有嵌套映射
 handlerowvaluesforsimpleresultmap(rsw, resultmap, resulthandler, rowbounds, parentmapping);
 }
 }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void handlerowvaluesforsimpleresultmap(resultsetwrapper rsw, resultmap resultmap, resulthandler<?> resulthandler, rowbounds rowbounds, resultmapping parentmapping)
 throws sqlexception {
 defaultresultcontext<object> resultcontext = new defaultresultcontext<>();
 resultset resultset = rsw.getresultset();
 // 跳過多少行,到達(dá)指定記錄位置,如在傳參的時候傳入了rowbounds,則會根據(jù)該類的offset值跳到指定記錄位置
 skiprows(resultset, rowbounds);
 // shouldprocessmorerows 用來檢測是否能繼續(xù)對后續(xù)的結(jié)果進(jìn)行映射
 while (shouldprocessmorerows(resultcontext, rowbounds) && !resultset.isclosed() && resultset.next()) {
 //用來處理resultmap節(jié)點(diǎn)中配置了discriminator節(jié)點(diǎn),這里忽略掉
 resultmap discriminatedresultmap = resolvediscriminatedresultmap(resultset, resultmap, null);
 // 得到的結(jié)果就是sql執(zhí)行后的一行記錄,如返回user對象信息,則rowvalue就代表一個user實(shí)例,里面已經(jīng)有值了
 object rowvalue = getrowvalue(rsw, discriminatedresultmap, null);
 //保存數(shù)據(jù)
 storeobject(resulthandler, resultcontext, rowvalue, parentmapping, resultset);
 }
 }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private object getrowvalue(resultsetwrapper rsw, resultmap resultmap, string columnprefix) throws sqlexception {
 final resultloadermap lazyloader = new resultloadermap();
 // 創(chuàng)建對象,可以理解為對resultmap節(jié)點(diǎn)的type屬性值,進(jìn)行了反射處理,得到了一個對象,但屬性值都是默認(rèn)值。
 object rowvalue = createresultobject(rsw, resultmap, lazyloader, columnprefix);
 if (rowvalue != null && !hastypehandlerforresultobject(rsw, resultmap.gettype())) {
 final metaobject metaobject = configuration.newmetaobject(rowvalue);
 boolean foundvalues = this.useconstructormappings;
 //是否需要自動映射,有三種映射,分別為none,partial,full,默認(rèn)第二種,處理非嵌套映射,可通過automappingbehavior 配置
 if (shouldapplyautomaticmappings(resultmap, false)) {
 // 映射resultmap中未明確指定的列,如類中含有username屬性,但是resultmap中沒配置,則通過這個進(jìn)行數(shù)據(jù)映射,還是可以查詢到結(jié)果
 foundvalues = applyautomaticmappings(rsw, resultmap, metaobject, columnprefix) || foundvalues;
 }
 // 處理resultmap中指定的列
 foundvalues = applypropertymappings(rsw, resultmap, metaobject, lazyloader, columnprefix) || foundvalues;
 foundvalues = lazyloader.size() > 0 || foundvalues;
 // 如果沒查詢到結(jié)果,但配置可返回空對象(指的是沒有設(shè)置屬性值得對象),則返回空對象,否則返回null
 rowvalue = foundvalues || configuration.isreturninstanceforemptyrow() ? rowvalue : null;
 }
 return rowvalue;
 }

這里只介紹resultmap中有明確指定的列

?
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
33
34
35
36
37
38
39
40
41
42
43
private boolean applypropertymappings(resultsetwrapper rsw, resultmap resultmap, metaobject metaobject, resultloadermap lazyloader, string columnprefix)
 throws sqlexception {
 // 獲取數(shù)據(jù)字段名
 final list<string> mappedcolumnnames = rsw.getmappedcolumnnames(resultmap, columnprefix);
 boolean foundvalues = false;
 // 獲取的數(shù)據(jù)就是resultmap節(jié)點(diǎn)中配置的result節(jié)點(diǎn),有多個result節(jié)點(diǎn),這個集合大小就是多少
 // 里面存儲的是屬性名/字段名等信息
 final list<resultmapping> propertymappings = resultmap.getpropertyresultmappings();
 for (resultmapping propertymapping : propertymappings) {
 string column = prependprefix(propertymapping.getcolumn(), columnprefix);
 // 是否有嵌套映射
 if (propertymapping.getnestedresultmapid() != null) {
 // the user added a column attribute to a nested result map, ignore it
 column = null;
 }
 // 針對1來說一般常與嵌套查詢配合使用
 // 2 判斷屬性基本映射
 // 3 多結(jié)果集的一個處理
 if (propertymapping.iscompositeresult()// 1
  || (column != null && mappedcolumnnames.contains(column.touppercase(locale.english)))// 2
  || propertymapping.getresultset() != null) {// 3
 // 獲取當(dāng)前column字段對于的值,有用到typehandler來進(jìn)行參數(shù)的一個轉(zhuǎn)換
 object value = getpropertymappingvalue(rsw.getresultset(), metaobject, propertymapping, lazyloader, columnprefix);
 
 //獲取類的屬性字段名
 final string property = propertymapping.getproperty();
 if (property == null) {
  continue;
 } else if (value == deferred) {// 類似占位符。處理懶加載數(shù)據(jù)
  foundvalues = true;
  continue;
 }
 if (value != null) {
  foundvalues = true;
 }
 if (value != null || (configuration.iscallsettersonnulls() && !metaobject.getsettertype(property).isprimitive())) {
  // 進(jìn)行設(shè)置屬性值
  metaobject.setvalue(property, value);
 }
 }
 }
 return foundvalues;
 }

或許有人奇怪為啥沒看到查詢的對象有set操作,值就到了對象里面去了,這里全是metaobject給你操作了,具體的,大家可以自行了解這個類,只能說這個類的功能很強(qiáng)大。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對服務(wù)器之家的支持。

原文鏈接:https://www.cnblogs.com/qm-article/p/10588627.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人在线观看免费观看 | 黄色片网站在线免费观看 | 小雪奶水翁胀公吸小说最新章节 | 欧日韩在线视频 | 久久精品在线免费观看 | 国产精品久久久久久久hd | 日韩精品久久久久久久九岛 | 万圣街在线观看免费完整版 | 精品国产亚洲人成在线 | 久久综合一区 | 美女视频大全网站免费 | 精品国产乱码一区二区 | 一级毛片免费一级 | 欧美14一15sex性hd | 国产69精品久久99不卡免费版 | 日韩视频1| 成年性羞羞视频免费观看 | 91在线看黄 | 日韩毛片一区二区三区 | 男人的天堂视频网站 | 久久精品操| 免费看真人a一级毛片 | 青草视频在线观看视频 | 中文字幕在线播放第一页 | 精品中文一区 | 看毛片免费 | 久久伊人国产精品 | 免费在线性爱视频 | 国产成人精品二区 | 日日狠狠久久偷偷四色综合免费 | 国产精品久久久久久久久久尿 | 精品一区二区在线播放 | 狠狠婷婷综合久久久久久妖精 | 成人在线免费观看小视频 | 欧美日韩手机在线观看 | 久久精品免费国产 | 国产 日韩 亚洲 欧美 | 色污视频 | 美女av在线免费观看 | 免费国产在线视频 | 欧美亚洲另类在线 |