MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解
前言
上文講的MyBatis部署運行且根據(jù)官網(wǎng)運行了一個demo:一步到位部署運行MyBatis3源碼<保姆級>
jdbc
再貼一個JDBC運行的測試方法,流程為:
- 加載JDBC驅(qū)動;
- 獲取數(shù)據(jù)庫連接;
- 創(chuàng)建JDBC Statements對象;
- 設(shè)置SQL語句的傳入?yún)?shù);
- 執(zhí)行SQL語句并獲得查詢結(jié)果;
- 對查詢結(jié)果進(jìn)行轉(zhuǎn)換處理并將處理結(jié)果返回;
- 釋放相關(guān)資源(關(guān)閉Connection,關(guān)閉Statement,關(guān)閉ResultSet);
@Test
public void jdbcTest(){
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/news?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true";
String user = "root";
String pwd = "root123456";
Connection connection=null;
ResultSet rs=null;
PreparedStatement stmt=null;
try {
Class.forName(driver);
//獲取數(shù)據(jù)庫連接
connection = DriverManager.getConnection(url,user,pwd);
String sql = "select * from t_level where name=?";
//創(chuàng)建Statement對象(每一個Statement為一次數(shù)據(jù)庫執(zhí)行請求)
stmt=connection.prepareStatement(sql);
//設(shè)置傳入?yún)?shù)
stmt.setString(1,"zhangsan");
//執(zhí)行SQL語句
rs = stmt.executeQuery(sql);
ResultSetMetaData metaData =rs.getMetaData();
//處理查詢結(jié)果-----此處未做操作
int columnCount= metaData.getColumnCount();
System.out.println(columnCount);
} catch (Exception e) {
e.printStackTrace();
}finally {
try{
//關(guān)閉結(jié)果集
if(rs!=null){
rs.close();
rs=null;
}
//關(guān)閉執(zhí)行
if(stmt!=null){
stmt.close();
stmt=null;
}
if(connection!=null){
connection.close();
connection=null;
}
}catch(SQLException e){
e.printStackTrace();
}
}
}傳統(tǒng)JDBC弊端
- JDBC 底層沒有用連接池,操作數(shù)據(jù)庫需要頻繁的創(chuàng)建和關(guān)閉連接,消耗很大的資源;
- 原生的 JDBC 代碼在 Java 中,一旦需要修改 SQL,Java 需要整體編譯,不利于系統(tǒng)維護(hù);
- 使用 PreparedStatement 預(yù)編譯的話,對變量進(jìn)行設(shè)置 1、2、3 等數(shù)字,這樣的序號不利于維護(hù);
- 返回 result 結(jié)果集也需要硬編碼。
思考
拿JDBC測試用例和上文mybatis的測試用例對比,可以發(fā)現(xiàn)哪些些共同點?
@Test
public void test() throws IOException {
InputStream input = Resources.getResourceAsStream("SqlSessionConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(input);
SqlSession sqlSession = sessionFactory.openSession();
LevelDao dao = sqlSession.getMapper(LevelDao.class);
List<Level> all = dao.findAll();
}
首先他們都要有數(shù)據(jù)源,這是毋庸置疑的。其次還要有執(zhí)行sql語句,再有就是執(zhí)行操作。
源碼分析
接下來進(jìn)入到源碼分析階段。
由于我們是根據(jù)官網(wǎng) Building SqlSessionFactory from XML的方式來測試demo的,接下來我們的解析就按照XML文件配置形式來講解。
獲取數(shù)據(jù)源
數(shù)據(jù)源4大元素包括:驅(qū)動、 url、 用戶名、 密碼。
在看代碼之前,先看一下我們的配置文件結(jié)構(gòu)。

mybatis是什么時候獲取到數(shù)據(jù)源的呢?要從測試方法生成SqlSessionFactory說起。
通過斷點進(jìn)入到SqlSessionFactoryBuilder的build方法中,方法體就兩行關(guān)鍵代碼,首先new了一個XML 配置生成器,接著調(diào)用了其parse()生成一個Configuration對象。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
parse方法執(zhí)行了下面這條語句:
parseConfiguration(parser.evalNode("/configuration"));
parser.evalNode會生成一個mybatis封裝的XNode對象,copy后發(fā)現(xiàn)就是我們配置文件中<configuration>標(biāo)簽中的內(nèi)容。


進(jìn)入到parseConfiguration方法中,可以看出好多方法的字符串參數(shù)都和我們<configuration>標(biāo)簽中的一些標(biāo)簽名稱相同。沒錯,每一步都是去掃描到對應(yīng)參數(shù)的標(biāo)簽內(nèi)容從而進(jìn)行一些配置處理。
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
我們此處不研究其他處內(nèi)容,直接看environmentsElement方法的內(nèi)容。root.evalNode("environments")返回的XNode對象的value就是我們的environments標(biāo)簽內(nèi)容。


進(jìn)入到environmentsElement方法中,會循環(huán)遍歷下一級的environment,此處便是解析xml配置多數(shù)據(jù)源的地方。
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
//xml配置多數(shù)據(jù)源
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//<dataSource></dataSource>
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
//獲得到數(shù)據(jù)庫源
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
dataSourceElement方法會拿到dataSource標(biāo)簽的內(nèi)容生成一個DataSourceFactory ,并根據(jù)我們的配置給其屬性賦值。
通過getDataSource()方法便可以拿到我們的數(shù)據(jù)源。
最后調(diào)用configuration.setEnvironment給到全局配置中的。
執(zhí)行流程圖如下:

總結(jié)
到此這篇關(guān)于MyBatis3源碼解析之如何獲取數(shù)據(jù)源的文章就介紹到這了,更多相關(guān)MyBatis3獲取數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot基于AbstractRoutingDataSource實現(xiàn)多數(shù)據(jù)源動態(tài)切換
本文主要介紹了SpringBoot基于AbstractRoutingDataSource實現(xiàn)多數(shù)據(jù)源動態(tài)切換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
導(dǎo)入renren-fast出現(xiàn)問題以及解決方案
文章介紹了在導(dǎo)入renren-fast項目時遇到的maven繼承parent問題,并提供了解決方案,即在pom文件中添加``標(biāo)簽,此外,還詳細(xì)解釋了Maven的``標(biāo)簽的作用以及MAVEN構(gòu)建jar包時的查找順序2024-11-11
SpringBoot靜態(tài)資源的訪問方法詳細(xì)介紹
最近在做SpringBoot項目的時候遇到了“白頁”問題,通過查資料對SpringBoot訪問靜態(tài)資源做了總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09

