Mybatis 簡介與入門
目錄
1. Mybatis是什麼?
Mybatis(3.x版本以前叫 ibatis)是一款一流的支援自定義 SQL、儲存過程和高階對映的持久化框架。Mybatis 幾乎消除了所有的 JDBC 程式碼,也基本不需要手工去設定引數和獲取檢索結果。Mybatis 能夠使用簡單的 XML 格式或者註解來進行配置,能夠對映基本資料元素、Map 介面和 POJOs(普通 java 物件)到資料庫的記錄。
1.1 Mybatis的發展
Mybatis 的發展歷程中有兩個重要版本 2.x 和 3.x,3.x版本上 Mybatis 的配置更加簡潔,我現在所使用的就是 mybatis-3.4.5。
1.2 Mybatis vs JDBC SQL
對比 | Mybatis | JDBC SQL |
連線 | 託管 | 編碼 |
SQL | 隔離/集中 | 混合/分散 |
快取 | 兩級快取 | 不支援 |
結果對映 | 自動對映 | 硬編碼 |
維護性 | 高 | 低 |
2. 開始使用Mybatis
- 在 IDEA 中安裝 Mybatis 外掛(Free Mybatis Plugin)
- IDEA Settings -> Plugins -> Browse repositories -> Free Mybatis Plugin
- 安裝完成後重啟IDEA
- 準備 Mybatis 專案
- 建立一個 Maven 的 Application 專案
- 在 pom.xml 中新增 Mybatis 依賴,org.mybatis:mybatis:3.4.5
- pom.xml 中新增 JDBC 驅動依賴,比如:mysql:mysql-connector-java:5.1.46
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> </dependencies>
- 準備資料庫
- 建立資料庫
- 建立資料庫表
2.1 構建 SqlSessionFactory
2.1.1 XML 構建
每個基於Mybatis的應用都是以一個SqlSessionFactory的例項為中心的。SqlSessionFactory的例項可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置檔案或一個預先定製的 Configuration 的例項構建出 SqlSessionFactory 的例項。
- 建立 Mybatis 配置檔案(mybatis-config.xml 歸檔到 src/main/resources/mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/memo"/>
<property name="username" value="root"/>
<property name="password" value="xyxy"/>
</dataSource>
</environment>
<environment id="prod">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/memo"/>
<property name="username" value="root"/>
<property name="password" value="xyxy"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/MemoGroupMapper.xml"/>
</mappers>
</configuration>
從 XML 檔案中構建 SqlSessionFactory 的例項非常簡單,建議使用類路徑下的資原始檔進行配置。但是也可以使用任意的輸入流(InputStream)例項,包括字串形式的檔案路徑或者 file:// 的 URL 形式的檔案路徑來配置。
Mybatis 包含一個名叫 Resources 的工具類,它包含一些實用方法,可以非常容易從 classpath 或其他位置家在資原始檔。
public static void main(String[] args) {
try {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsReader("mybatis-config.xml")
);
System.out.println(sqlSessionFactory);
} catch (IOException e) {
e.printStackTrace();
}
}
2.1.2 編碼構建
如果你更願意直接從 Java 程式而不是 XML 檔案中建立 configuration,或者建立你自己的 configuration 構建器,Mybatis 也提供了完整的配置類,提供所有和 XML 檔案相同功能的配置項。
// mybatis提供的資料庫連線池
DataSource dataSource = new PooledDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(MemoGroupMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
該例中,configuration 添加了一個對映類(mapper class)。對映器類是 Java 類,它們包含 SQL 對映語句的註解,從而避免了 XML 檔案的依賴。不過,由於 Java 註解的一些限制加之某些 Mybatis 對映的複雜性,XML 對映對於大多數高階對映(比如:巢狀 join 對映)來說仍然是必須的。有鑑於此,如果存在一個對等的 XML 配置檔案的話,Mybatis 會自動查詢並載入它(在這種情況下,MemoGroupMapper.xml 將會基於類路徑和 MemoGroupMapper.class 的類名被載入進來)。
2.2 使用 SqlSession
既然有了 SqlSessionFactory,顧名思義,我們就可以從中獲得 SqlSession 的例項了。SqlSession 完全包含了面向資料庫執行 SQL 命令所需的所有方法。可以通過 SqlSession 例項來直接執行已對映的 SQL 語句。例如:
SqlSession session = sqlSessionFactory.openSession();
// 自動提交
// SqlSession session = sqlSessionFactory.openSession(true);
try {
MemoGroup memoGroup = (MemoGroup)
session.selectOne("com.lwstudy.mybatis.mapper.MemoGroupMapper.selectMemoGroup", 1);
} finally {
session.close();
}
誠然這種方式能夠正常工作,並且對於使用舊版本MyBatis 的使用者來說也比較熟悉,不過現在有了一種更直白的方式。使用對於給定語句能夠合理描述引數和返回值的介面(比如說MemoGroupMapper.class),現在不但可以執行更清晰和型別安全的程式碼,而且還不用擔心易錯的字串字面值以及強制型別轉換。例如:
SqlSession session = sqlSessionFactory.openSession();
// 自動提交
// SqlSession session = sqlSessionFactory.openSession(true);
try {
MemoGroupMapper mapper = session.getMapper(MemoGroupMapper.class);
MemoGroup memoGroup = mapper.selectMemoGroup(1);
} finally {
session.close();
}
SQL 對映檔案內容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lwstudy.mybatis.mapper.MemoGroupMapper">
<resultMap id="memoGroup" type="com.lwstudy.mybatis.entity.MemoGroup">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="createdTime" column="created_time" jdbcType="TIMESTAMP"/>
<result property="modifyTime" column="modify_time" jdbcType="TIMESTAMP"/>
</resultMap>
<select id="selectMemoGroup" resultType="com.lwstudy.mybatis.entity.MemoGroup">
select id, name, created_time, modify_time from memo_group
where id=#{id}
</select>
</mapper>
3. Mybatis的核心概念
3.1 核心型別
3.1.1 SqlSessionFactoryBuilder
sqlSessionFactoryBuilder 這個類可以在任何時候被例項化、使用和銷燬。一旦創造了 SqlSessionFactory 就不需要再保留它。所以 SqlSessionFactoryBuilder 例項的最好的作用域就是方法體內(即一個本地方法變數)。雖然能重用 SqlSessionFactoryBuilder 建立多個 SqlSessionFactory 例項,但最好不要把時間、資源放在解析 XML 檔案上,而要從中解放出來做最重要的事情。
3.1.2 SqlSessionFactory
sqlSessionFactory 一旦建立,SqlSessionFactory 將會存在於應用程式整個執行生命週期中。很少或根本沒有理由去銷燬它或者重新建立它。最佳實踐是不要在一個應用中多次創 SqlSessionFactory。這樣做會被視為“沒品味”,SqlSessionFactory 最好的作用域範圍是一個應用的生命週期範圍。這可以由多種方式來實現,最簡單的方式是使用 Singleton 模式或靜態 Singleton 模式。但這不是被廣泛接受的最佳做法,相反,您可能更願意使用像 Google Guice 或Spring 的依賴注入方式。這些框架允許您創造一個管理器,用於管理 SqlSessionFactory 的生命週期。
3.1.3 SqlSession
sqlSession 每個執行緒都有一個 SqlSession 例項,SqlSession 例項是不被共享的,並且不是執行緒安全的。因此最好的作用域是request 或者 method。決不要用一個靜態欄位或者一個類的例項欄位來儲存 SqlSession 例項引用。也不要用任何一個管理作用域,如 Servlet 框架中的 HttpSession,來儲存 SqlSession 的引用。如果您正在用一個 WEB 框架,可以把 SqlSession 的作用域看作類似於 HTTP 的請求範圍。也就是說,在收到一個 HTTP 請求,可以開啟一個 SqlSession,當把 response 返回時,就可以把 SqlSession 關閉。關閉會話是非常重要的,應該要確保會話在一個 finally 塊中被關閉。
3.1.4 Mapper interface
mapper 是建立來繫結對映語句的介面,該 Mapper 例項是從 SqlSession 得到的。因此,所有 mapper 例項的作用域跟建立它的 SqlSession 一樣。但是,mapper 例項最好的作用域是 method,也就是他們應該在方法內被呼叫,使用完即被銷燬。並且 mapper 例項不用顯式的被關閉。雖然把 mapper 例項保持在一個 request 範圍(與 SqlSession 相似)不會產生太大的問題,但是,在這個層次管理太多資源可能會失控。保持簡單,就是讓 Mappers 保持在一個方法內。
3.1.5 核心類的實踐總結
類 | 作用域 |
SqlSessionFactoryBuilder | method |
SqlSessionFactory | application(單例) |
SqlSession | request、thread、method(非執行緒安全) |
Mapper interface | request、thread、method |
3.2 SQL 的名稱空間
3.2.1 SQL 對映簡述
Mybatis 中關於 SQL 的部分主要集中在 SQL 對映,其支援 SQL 對映的方式有兩種,一種是基於 XML 的方式,一種是基於註解。
Mybatis 的所有特性都是可以通過 XML 配置的方式進行定義,通常情況都是通過 XML 配置來使用 Mybatis 的 SQL 對映,主要原因有以下幾種:
- XML 配置支援 Mybatis 的所有特性
- XML 的維護性、可讀性強
- 開發工具對 Mybatis 的 SQL 對映 XML 配置具有良好的支援
- XML 配置集中管理 SQL 是使用 Mybatis 的一個重要因素
- 註解方式難以處理複雜 SQL
3.2.2 SQL 對映案例
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lwstudy.mybatis.mapper.MemoGroupMapper">
<resultMap id="memoGroup" type="com.lwstudy.mybatis.entity.MemoGroup">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="createdTime" column="created_time" jdbcType="TIMESTAMP"/>
<result property="modifyTime" column="modify_time" jdbcType="TIMESTAMP"/>
</resultMap>
<select id="selectMemoGroup" resultMap="memoGroup" resultType="com.lwstudy.mybatis.entity.MemoGroup">
select id, name, created_time, modify_time from memo_group
where id=#{id}
</select>
</mapper>
上面對映檔案中的 com.lwstudy.mybatis.mapper.MemoGroupMapper 就是名稱空間名稱,selectMemoGroup 是 SQL 的名稱,在同一個名稱空間下,SQL 名稱是唯一的。
第一種查詢
SqlSession sqlSession = sqlSessionFactory.openSession();
MemoGroup memoGroup = sqlSession.selectOne(
"com.lwstudy.mybatis.mapper.MemoGroupMapper.selectMemoGroup", 1);
通過 名稱空間 + SQL 名稱 對映到具體的 SQL。
第二種查詢
MemoGroupMapper memoGroupMapper = sqlSession.getMapper(MemoGroupMapper.class);
MemoGroup memoGroup = memoGroupMapper.selectMemoGroup(1);
通過介面類對映,相比第一種查詢有以下幾個優勢:
- 不依賴字串,不容易出錯,所以安全。
- 通過 IDE 的自動完成功能,可以快速通過對映類導航到具體的 SQL 語句。
- 不需要關注方法返回型別,不需要進行型別強轉。