多結果集
下面的例子來自
有兩條sql語句
select * from blog where id = #
select * from author where id = #
有下xml配置
)}
可以看到,假設不支援多結果集,那麼對於blog關聯了author的情況就需要多條sql語句來執行了,容易產生n+1的問題
現在的jdbc驅動支援多資料集的返回了,所以只要執行一次即可
那麼拿到的第乙個resultset就不包含author的資訊,在mybatis中是先通過乙個pendingrelation來記錄父屬性對映,這裡的父屬性對映從這裡的配置來看,它就是author屬性
mybatis首先建立乙個pendingrelation,它有兩個屬性
private static class pendingrelation
這個author需要迴圈到下乙個resultset時才能真正獲取都值
下面繼續嵌入resultmap的分析,對於嵌入的,通常我們將使用多表關聯的方式去執行sql
//defaultresultcontext 維護這生成的返回物件
final defaultresultcontextresultcontext = new defaultresultcontext();
//跳過rowbounds.getoffset
skiprows(rsw.getresultset(), rowbounds);
object rowvalue = previousrowvalue;
//shouldprocessmorerows 表示是否繼續 受rowbounds.getlimit的限制
while (shouldprocessmorerows(resultcontext, rowbounds) && rsw.getresultset().next())
//建立值
//(*1*)
rowvalue = getrowvalue(rsw, discriminatedresultmap, rowkey, null, partialobject);
} else }}
previousrowvalue = null;
} else if (rowvalue != null)
} //(*1*)
final string resultmapid = resultmap.getid();
//分組物件
object resultobject = partialobject;
if (resultobject != null) else
//應用屬性對映
//儲存ancestorobjects.put(resultmapid, resultobject);
putancestor(resultobject, resultmapid, columnprefix);
//獲取嵌入的resultmap,然後建立其物件,最後設定到父物件中(metaobject)
//(*1*)
//移除父物件
ancestorobjects.remove(resultmapid);
foundvalues = lazyloader.size() > 0 || foundvalues;
resultobject = foundvalues ? resultobject : null;
}if (combinedkey != cachekey.null_cache_key)
}return resultobject;
}//(*1*)
boolean foundvalues = false;
//獲取嵌入的nestedresultmapid
//如果存在嵌入的resultmapid並且沒有指定resultset(有表示是多結果集的操作,不屬於嵌入resultmap)
try
} else }}
} catch (sqlexception e) }}
return foundvalues;
} 所以mybatis,對於嵌入的resultmap是通過快取key來分組的,設定嵌入的值,如果嵌入的值還有嵌入的值,可以繼續遞迴獲取值,繼續嵌入,還會快取resultmapid -> 物件的關係,因為有些物件之間會相互引用,那就沒有必要重新建立了。
比如我們有blog物件,它內部又乙個屬性autors,它是乙個list,那麼對於join查詢,我們肯定要根據resultset返回的結果進行分組,那麼分組的key是怎麼建立的呢?首先對於第一層物件的cachekey建立**如下:
final cachekey cachekey = new cachekey();
//首先resultmapid,表示這個結果集所屬resultmap
cachekey.update(resultmap.getid());
//如果沒有主鍵對映
//並且對映的屬性是map的話,那麼將所有的欄位名和對應的字段值設定為cachekey的一部分
if (map.class.isassignablefrom(resultmap.gettype())) else
} else
//如果沒有對映任何字段,返回cachekey.null_cache_key
//按道理,如果存在乙個字段對映都會update 2次,比如只有乙個主鍵的情況下就是update 2次
if (cachekey.getupdatecount() < 2)
return cachekey;
} 對於嵌入屬性的嵌入屬性,依次通過以下方法設定cachekey
private cachekey org.apache.ibatis.executor.resultset.defaultresultsethandler#combinekeys(cachekey rowkey, cachekey parentrowkey) catch (clonenotsupportedexception e)
combinedkey.update(parentrowkey);
return combinedkey;
}return cachekey.null_cache_key;
}
非常簡單,就是將父cachekey作為自己cachekey的一部分,保證唯一性。 7 SQL優化技術
7.1 改變訪問結構 7.2 修改sql語句 7.3 提示hint 提示的分類 初始化引數提示 all rows,cursor sharing extract,dynamic sampling,first rows,gather plan statistics 查詢轉化提示 no eliminate...
資料庫優化專題 7 SQL語句優化
資料庫優化專題 1 表的主鍵用數字還是uuid 資料庫優化專題 2 邏輯刪除還是物理刪除 資料庫優化專題 3 千萬記錄如何快速分頁 資料庫優化專題 4 讀多寫少和讀多寫多 資料庫優化專題 5 刪改資料如何避免鎖表 資料庫優化專題 6 如何避免偷換交易中的商品資訊 資料庫優化專題 7 sql語句優化 ...
sql執行過程
程式中寫的一條sql傳送到伺服器端 查詢此條sql是否存在執行計畫 如果存在則直接呼叫已經編譯好的執行計畫 否則進入下一步。如果sql計畫快取中沒有對應的執行計畫,則進行語法校驗 檢視是否存在語法錯誤 如果語法沒有錯誤則進行語義校驗,例如,表名,列名,儲存過程等等資料庫物件是否真正存在 如果語義沒有...