MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解
前言
上文講的MyBatis部署運行且根據(jù)官網(wǎng)運行了一個demo:一步到位部署運行MyBatis3源碼<保姆級>
jdbc
再貼一個JDBC運行的測試方法,流程為:
- 加載JDBC驅動;
- 獲取數(shù)據(jù)庫連接;
- 創(chuàng)建JDBC Statements對象;
- 設置SQL語句的傳入?yún)?shù);
- 執(zhí)行SQL語句并獲得查詢結果;
- 對查詢結果進行轉換處理并將處理結果返回;
- 釋放相關資源(關閉Connection,關閉Statement,關閉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);
//設置傳入?yún)?shù)
stmt.setString(1,"zhangsan");
//執(zhí)行SQL語句
rs = stmt.executeQuery(sql);
ResultSetMetaData metaData =rs.getMetaData();
//處理查詢結果-----此處未做操作
int columnCount= metaData.getColumnCount();
System.out.println(columnCount);
} catch (Exception e) {
e.printStackTrace();
}finally {
try{
//關閉結果集
if(rs!=null){
rs.close();
rs=null;
}
//關閉執(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)建和關閉連接,消耗很大的資源;
- 原生的 JDBC 代碼在 Java 中,一旦需要修改 SQL,Java 需要整體編譯,不利于系統(tǒng)維護;
- 使用 PreparedStatement 預編譯的話,對變量進行設置 1、2、3 等數(shù)字,這樣的序號不利于維護;
- 返回 result 結果集也需要硬編碼。
思考
拿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ù)官網(wǎng) Building SqlSessionFactory from XML的方式來測試demo的,接下來我們的解析就按照XML文件配置形式來講解。
獲取數(shù)據(jù)源
數(shù)據(jù)源4大元素包括:驅動、 url、 用戶名、 密碼。
在看代碼之前,先看一下我們的配置文件結構。

mybatis是什么時候獲取到數(shù)據(jù)源的呢?要從測試方法生成SqlSessionFactory說起。
通過斷點進入到SqlSessionFactoryBuilder的build方法中,方法體就兩行關鍵代碼,首先new了一個XML 配置生成器,接著調用了其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>標簽中的內容。


進入到parseConfiguration方法中,可以看出好多方法的字符串參數(shù)都和我們<configuration>標簽中的一些標簽名稱相同。沒錯,每一步都是去掃描到對應參數(shù)的標簽內容從而進行一些配置處理。
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);
}
}
我們此處不研究其他處內容,直接看environmentsElement方法的內容。root.evalNode("environments")返回的XNode對象的value就是我們的environments標簽內容。


進入到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標簽的內容生成一個DataSourceFactory ,并根據(jù)我們的配置給其屬性賦值。
通過getDataSource()方法便可以拿到我們的數(shù)據(jù)源。
最后調用configuration.setEnvironment給到全局配置中的。
執(zhí)行流程圖如下:

總結
到此這篇關于MyBatis3源碼解析之如何獲取數(shù)據(jù)源的文章就介紹到這了,更多相關MyBatis3獲取數(shù)據(jù)源內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot項目中引入本地依賴jar包并打包到lib文件夾中
這篇文章主要介紹了springboot項目中引入本地依賴jar包,如何打包到lib文件夾中,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
使用Springboot根據(jù)配置文件動態(tài)注入接口實現(xiàn)類
這篇文章主要介紹了使用Springboot根據(jù)配置文件動態(tài)注入接口實現(xiàn)類,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

