掃二維碼與項目經理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流
其實很多程序員在剛開始做編程或者新加入一家公司時,都沒有多少機會可以做一個新項目,大部分時候都是在老項目上不斷的迭代更新。在這個過程你可能要學習N個前人留下的各式各樣的風格迥異的代碼片段,在這些縱橫交錯的流程中,找到一席之地,把自己的ifelse加進去。

康保網站建設公司成都創(chuàng)新互聯,康保網站設計制作,有大型網站制作公司豐富經驗。已為康保近千家提供企業(yè)網站建設服務。企業(yè)網站搭建\成都外貿網站制作要多少錢,請找那個售后服務好的康保做網站的公司定做!
雖然這樣胡亂的加ifelse,剛上手就“擺爛”的心態(tài),讓人很難受。但要想在已經被壓縮的工期下,還能交付出高質量的代碼其實也很難完成,所以一部分研發(fā)被逼到能用就行,能跑就可以。
但說回來,其實不能逐步清理一片屎山,讓代碼在你的手上逐步清晰、整潔、干凈,很多時候也是作為碼農自身經驗的不足,不懂得系統(tǒng)重構、不了解設計原則、不熟悉業(yè)務背景、不清楚產品走向等等原因造成的。所以最好的辦法是提升自身的能力,每接到一次需求都有一些技術上的改變,既然它是屎山,那就當做打怪升級了,修一點、改一塊、補一片,總會在你手上越來越易于維護和擴展的。
在我們漸進式的逐步實現 Mybatis 框架過程中,首先我們要有一個目標導向的思路,也就是說 Mybatis 的核心邏輯怎么實現。
其實我們可以把這樣一個 ORM 框架的目標,簡單的描述成是為了給一個接口提供代理類,類中包括了對 Mapper 也就是 xml 文件中的 SQL 信息(類型、入參、出參、條件)進行解析和處理,這個處理過程就是對數據庫的操作以及返回對應的結果給到接口。如圖 4-1
圖 4-1 ORM 框架核心流程
那么按照 ORM 核心流程的執(zhí)行過程,我們本章節(jié)就需要在上一章節(jié)的基礎上,繼續(xù)擴展對 Mapper 文件的解析以及提取出對應的 SQL 文件。并在當前這個階段,可以滿足我們調用 DAO 接口方法的時候,可以返回 Mapper 中對應的待執(zhí)行 SQL 語句。為了不至于把整個工程撐大,小傅哥會帶著大家逐步完成這些內容,所以本章節(jié)暫時不會對數據庫進行操作,待后續(xù)逐步實現
結合上一章節(jié)我們使用了 MapperRegistry 對包路徑進行掃描注冊映射器,并在 DefaultSqlSession 中進行使用。那么在我們可以把這些命名空間、SQL描述、映射信息統(tǒng)一維護到每一個 DAO 對應的 Mapper XML 的文件以后,其實 XML 就是我們的源頭了。通過對 XML 文件的解析和處理就可以完成 Mapper 映射器的注冊和 SQL 管理。這樣也就更加我們操作和使用了。如圖 4-2
圖 4-2 XML 文件解析注冊處理
mybatis-step-03
└── src
├── main
│ └── java
│ └── cn.bugstack.mybatis
│ ├── binding
│ │ ├── MapperMethod.java
│ │ ├── MapperProxy.java
│ │ ├── MapperProxyFactory.java
│ │ └── MapperRegistry.java
│ ├── builder
│ │ ├── xml
│ │ │ └── XMLConfigBuilder.java
│ │ └── BaseBuilder.java
│ ├── io
│ │ └── Resources.java
│ ├── mapping
│ │ ├── MappedStatement.java
│ │ └── SqlCommandType.java
│ └── session
│ ├── defaults
│ │ ├── DefaultSqlSession.java
│ │ └── DefaultSqlSessionFactory.java
│ ├── Configuration.java
│ ├── SqlSession.java
│ ├── SqlSessionFactory.java
│ └── SqlSessionFactoryBuilder.java
└── test
├── java
│ └── cn.bugstack.mybatis.test.dao
│ ├── dao
│ │ └── IUserDao.java
│ ├── po
│ │ └── User.java
│ └── ApiTest.java
└── resources
├── mapper
│ └──User_Mapper.xml
└── mybatis-config-datasource.xml
工程源碼:https://t.zsxq.com/bmqNFQ7
XML 解析和注冊類實現關系,如圖 4-2
圖 4-2 XML 解析和注冊類實現關系
源碼詳見:cn.bugstack.mybatis.session.SqlSessionFactoryBuilder
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader);
return build(xmlConfigBuilder.parse());
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}源碼詳見:cn.bugstack.mybatis.builder.xml.XMLConfigBuilder
public class XMLConfigBuilder extends BaseBuilder {
private Element root;
public XMLConfigBuilder(Reader reader) {
// 1. 調用父類初始化Configuration
super(new Configuration());
// 2. dom4j 處理 xml
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(new InputSource(reader));
root = document.getRootElement();
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Configuration parse() {
try {
// 解析映射器
mapperElement(root.element("mappers"));
} catch (Exception e) {
throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
return configuration;
}
private void mapperElement(Element mappers) throws Exception {
List mapperList = mappers.elements("mapper");
for (Element e : mapperList) {
// 解析處理,具體參照源碼
// 添加解析 SQL
configuration.addMappedStatement(mappedStatement);
}
// 注冊Mapper映射器
configuration.addMapper(Resources.classForName(namespace));
}
}
} **源碼詳見(配置項)**:cn.bugstack.mybatis.session.Configuration
public class Configuration {
/**
* 映射注冊機
*/
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
/**
* 映射的語句,存在Map里
*/
protected final Map mappedStatements = new HashMap<>();
public void addMapper(Class type) {
mapperRegistry.addMapper(type);
}
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
} 在配置類中添加映射器注冊機和映射語句的存放;
映射器注冊機是我們上一章節(jié)實現的內容,用于注冊 Mapper 映射器鎖提供的操作類。
另外一個 MappedStatement 是本章節(jié)新添加的 SQL 信息記錄對象,包括記錄:SQL類型、SQL語句、入參類型、出參類型等。詳細可參照源碼
源碼詳見:cn.bugstack.mybatis.session.defaults.DefaultSqlSession
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
@Override
public T selectOne(String statement, Object parameter) {
MappedStatement mappedStatement = configuration.getMappedStatement(statement);
return (T) ("你被代理了!" + "\n方法:" + statement + "\n入參:" + parameter + "\n待執(zhí)行SQL:" + mappedStatement.getSql());
}
@Override
public T getMapper(Class type) {
return configuration.getMapper(type, this);
}
} DefaultSqlSession 相對于上一章節(jié),小傅哥這里把 MapperRegistry mapperRegistry 替換為 Configuration configuration,這樣才能傳遞更豐富的信息內容,而不只是注冊器操作。
之后在 DefaultSqlSession#selectOne、DefaultSqlSession#getMapper 兩個方法中都使用 configuration 來獲取對應的信息。
目前 selectOne 方法中只是把獲取的信息進行打印,后續(xù)將引入 SQL 執(zhí)行器進行結果查詢并返回。
提供 DAO 接口和對應的 Mapper xml 配置
public interface IUserDao {
String queryUserInfoById(String uId);
}@Test
public void test_SqlSessionFactory() throws IOException {
// 1. 從SqlSessionFactory中獲取SqlSession
Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2. 獲取映射器對象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 3. 測試驗證
String res = userDao.queryUserInfoById("10001");
logger.info("測試結果:{}", res);
}
測試結果
07:07:40.519 [main] INFO cn.bugstack.mybatis.test.ApiTest - 測試結果:你被代理了!
方法:cn.bugstack.mybatis.test.dao.IUserDao.queryUserInfoById
入參:[Ljava.lang.Object;@23223dd8
待執(zhí)行SQL:
SELECT id, userId, userHead, createTime
FROM user
where id = ?
Process finished with exit code 0
從測試結果我們可以看到,目前的代理操作已經可以把我們從 XML 中解析的 SQL 信息進行打印了,后續(xù)我們將結合這部分的處理繼續(xù)完成數據庫的操作。

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流