本文收錄於模仿與學習MyBatis系列
系列的開始
在本系列的一開始,我還不打算記錄一個非常宏大的MyBatis世界的整體結構。原因很簡單,包括我在內的大部分初學者,在剛接觸這類框架前,都是一頭霧水的。像我當初去請教一些前輩,“MyBatis要怎麼學呢?”直接被一句“去把源碼和官方文檔看一遍”給堵了回來——那十幾個大模塊以及之間的交互,看了就讓人厭煩了,我還不懂MyBatis是什麼的情況下,又怎麼能體會這些架構和功能的意義和精妙呢?我想這種回答是不夠負責任的。
如果換作是我,以自己的學習經歷來說,我覺得不妨從最關心、最基礎的部分說起,比如:
一、 MyBatis拿來幹什麼?
MyBatis核心功能可以總結爲:當我調用一個Java方法時,等於在指定的數據庫,執行若干sql操作,並把執行結果轉爲一個Java類。 這段話可能有點繞 ,具體含義可以參考下面代碼裏寫的:
public interface BookMapper {
@Select("select * from book where author=#{name}")
List<Book> findByName(String name);
@Delete("delete from book where author=#{name}")
int deleteByName(String name);
}
public void test(SqlSession session) {
BookMapper mapper = session.getMapper(BookMapper.class);
List<Book> book = mapper.findByName("test");
}
注意test(session)方法。我們在MyBatis框架中,直接從一個接口(注意這是一個接口不是類),生成了一個可用的對象mapper。並且當我們執行mapper的方法findByName(“Mark”)時,等同於在我們的數據庫裏執行了select * from book where author=Mark
,把book表中author=Mark的書全部返回了出來,返回了一個List。(此處Book類裏的成員變量需與數據庫中的book一一對應)
二、怎麼執行sql語句
當我們要執行sql語句的時候,在Java代碼中到底做了什麼呢?
- 首先需要連接到指定的數據庫(得到Connection)
- 從連接中獲取sql容器(得到Statement)
用此容器執行一條sql語句(得到ResultSet)
結果的ResultSet中可以取出表裏的列名與對應的值。由於一共只有三個操作,就列一下代碼吧:
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
三、Session又是什麼
經常在使用框架時看到Session,那這個Session又是個什麼東西呢?先看下圖:
當我們通過數據庫信息(DataSource)訪問數據庫,並從數據庫取到一個連接(Connection)出來時,業務的執行還沒有真正開始。我們需要使用這個連接,執行一系列的sql語句,希望回滾、提交等等。而且最最重要的是,通常數據庫的返回值是這樣的:
而實際上我想要的是一個這樣的Java類:
那麼誰來負責:使用連接,執行sql,執行事務,把結果轉爲Java類等工作呢?在常規的這類框架中,我們把這一系列操作,全部抽象到與一個類對應,這個類的開始就是一切的開始,這個類的結束就是這一切的結束。通常我們將這個類稱爲Session,一個Session僅擁有一個對應的數據庫連接。
四、MyBatis中的Session
<T> T selectOne(String statement);
<T> T getMapper(Class<T> type);
雖然打開MyBatis的SqlSession接口,可以看到非常多方法,但歸納出來其實只有以上兩種。一是可以直接代入sql執行,另一種用法如下:
public interface BookMapper {
@Select("select * from book where name=#{name}")
Book findByName(String name);
}
public void test(SqlSession session) {
// 在session中生成一個可用的類
BookMapper mapper = session.getMapper(BookMapper.class);
Book book = mapper.findByName("test");
}
可以看到,這裏使用一個Session與一個Mapper.class,生成了一個可用的mapper對象,只要mapper對象執行方法,就對應的執行了方法上的註解內容。
它是怎樣實現的呢?其實非常簡單,生成mapper對象時,在它裏面存了session值。這樣在執行mapper.findByName("xxx")
時,實際上調用的是session.selectOne("select * from book where name=xxx")
,大體流程如下圖:
我們可以發現,MyBatis的核心功能其實不難。無非就是動態代理和jdbc操作,在後續的文章裏會逐個解釋這些概念,但在下一篇中,先實現一個基本的Session類。