鍍金池/ 教程/ Java/ mybatis – MyBatis 3 | 入門
Java API
SQL語句構(gòu)建器
Mapper XML 文件
XML 映射配置文件
mybatis – MyBatis 3 | 入門
Logging
動態(tài) SQL

mybatis – MyBatis 3 | 入門

安裝

要使用 MyBatis, 只需將 mybatis-x.x.x.jar 文件置于 classpath 中即可。

如果使用 Maven 來構(gòu)建項目,則需將下面的 dependency 代碼置于 pom.xml 文件中:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

從 XML 中構(gòu)建 SqlSessionFactory

每個基于 MyBatis 的應(yīng)用都是以一個 SqlSessionFactory 的實例為中心的。SqlSessionFactory 的實例可以通過SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個預(yù)先定制的 Configuration 的實例構(gòu)建出 SqlSessionFactory 的實例。

從 XML 文件中構(gòu)建 SqlSessionFactory 的實例非常簡單,建議使用類路徑下的資源文件進行配置。但是也可以使用任意的輸入流(InputStream)實例,包括字符串形式的文件路徑或者 file:// 的 URL 形式的文件路徑來配置。MyBatis 包含一個名叫 Resources 的工具類,它包含一些實用方法,可使從 classpath 或其他位置加載資源文件更加容易。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

XML 配置文件(configuration XML)中包含了對 MyBatis 系統(tǒng)的核心設(shè)置,包含獲取數(shù)據(jù)庫連接實例的數(shù)據(jù)源(DataSource)和決定事務(wù)范圍和控制方式的事務(wù)管理器(TransactionManager)。XML 配置文件的詳細(xì)內(nèi)容后面再探討,這里先給出一個簡單的示例:

<?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="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

當(dāng)然,還有很多可以在XML 文件中進行配置,上面的示例指出的則是最關(guān)鍵的部分。要注意 XML 頭部的聲明,用來驗證 XML 文檔正確性。environment 元素體中包含了事務(wù)管理和連接池的配置。mappers 元素則是包含一組 mapper 映射器(這些 mapper 的 XML 文件包含了 SQL 代碼和映射定義信息)。

不使用 XML 構(gòu)建 SqlSessionFactory

如果你更愿意直接從 Java 程序而不是 XML 文件中創(chuàng)建 configuration,或者創(chuàng)建你自己的 configuration 構(gòu)建器,MyBatis 也提供了完整的配置類,提供所有和 XML 文件相同功能的配置項。

    DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
    TransactionFactory transactionFactory = new JdbcTransactionFactory();
    Environment environment = new Environment("development", transactionFactory, dataSource);
    Configuration configuration = new Configuration(environment);
    configuration.addMapper(BlogMapper.class);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

注意該例中,configuration 添加了一個映射器類(mapper class)。映射器類是 Java 類,它們包含 SQL 映射語句的注解從而避免了 XML 文件的依賴。不過,由于 Java 注解的一些限制加之某些 MyBatis 映射的復(fù)雜性,XML 映射對于大多數(shù)高級映射(比如:嵌套 Join 映射)來說仍然是必須的。有鑒于此,如果存在一個對等的 XML 配置文件的話,MyBatis 會自動查找并加載它(這種情況下, BlogMapper.xml 將會基于類路徑和 BlogMapper.class 的類名被加載進來)。具體細(xì)節(jié)稍后討論。

從 SqlSessionFactory 中獲取 SqlSession

既然有了 SqlSessionFactory ,顧名思義,我們就可以從中獲得 SqlSession 的實例了。SqlSession 完全包含了面向數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法。你可以通過 SqlSession 實例來直接執(zhí)行已映射的 SQL 語句。例如:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
    } finally {
      session.close();
    }

誠然這種方式能夠正常工作,并且對于使用舊版本 MyBatis 的用戶來說也比較熟悉,不過現(xiàn)在有了一種更直白的方式。使用對于給定語句能夠合理描述參數(shù)和返回值的接口(比如說BlogMapper.class),你現(xiàn)在不但可以執(zhí)行更清晰和類型安全的代碼,而且還不用擔(dān)心易錯的字符串字面值以及強制類型轉(zhuǎn)換。

例如:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      BlogMapper mapper = session.getMapper(BlogMapper.class);
      Blog blog = mapper.selectBlog(101);
    } finally {
      session.close();
    }

現(xiàn)在我們來探究一下這里到底是怎么執(zhí)行的。

探究已映射的 SQL 語句

現(xiàn)在,或許你很想知道 SqlSession 和 Mapper 到底執(zhí)行了什么操作,而 SQL 語句映射是個相當(dāng)大的話題,可能會占去文檔的大部分篇幅。不過為了讓你能夠了解個大概,這里會給出幾個例子。

在上面提到的兩個例子中,一個語句應(yīng)該是通過 XML 定義,而另外一個則是通過注解定義。先看 XML 定義這個,事實上 MyBatis 提供的全部特性可以利用基于 XML 的映射語言來實現(xiàn),這使得 MyBatis 在過去的數(shù)年間得以流行。如果你以前用過 MyBatis,這個概念應(yīng)該會比較熟悉。不過 XML 映射文件已經(jīng)有了很多的改進,隨著文檔的進行會愈發(fā)清晰。這里給出一個基于 XML 映射語句的示例,它應(yīng)該可以滿足上述示例中 SqlSession 的調(diào)用。

<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

對于這個簡單的例子來說似乎有點小題大做了,但實際上它是非常輕量級的。在一個 XML 映射文件中,你想定義多少個映射語句都是可以的,這樣下來,XML 頭部和文檔類型聲明占去的部分就顯得微不足道了。文件的剩余部分具有很好的自解釋性。在命名空間"com.mybatis.example.BlogMapper"中定義了一個名為"selectBlog"的映射語句,這樣它就允許你使用指定的完全限定名"org.mybatis.example.BlogMapper.selectBlog"來調(diào)用映射語句,就像上面的例子中做的那樣:

    Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);

你可能注意到這和使用完全限定名調(diào)用 Java 對象的方法是相似的,之所以這樣做是有原因的。這個命名可以直接映射到在命名空間中同名的 Mapper 類,并在已映射的 select 語句中的名字、參數(shù)和返回類型匹配成方法。這樣你就可以向上面那樣很容易地調(diào)用這個對應(yīng) Mapper 接口的方法。不過讓我們再看一遍下面的例子:

    BlogMapper mapper = session.getMapper(BlogMapper.class);
    Blog blog = mapper.selectBlog(101);

第二種方法有很多優(yōu)勢,首先它不是基于字符串常量的,就會更安全;其次,如果你的 IDE 有代碼補全功能,那么你可以在有了已映射 SQL 語句的基礎(chǔ)之上利用這個功能。

提示命名空間的一點注釋

命名空間(Namespaces)在之前版本的 MyBatis 中是可選的,容易引起混淆因此是沒有益處的。現(xiàn)在的命名空間則是必須的,目的是希望能比只是簡單的使用更長的完全限定名來區(qū)分語句更進一步。

命名空間使得你所見到的接口綁定成為可能,盡管你覺得這些東西未必用得上,你還是應(yīng)該遵循這里的規(guī)定以防哪天你改變了主意。出于長遠(yuǎn)考慮,使用命名空間,并將它置于合適的 Java 包命名空間之下,你將擁有一份更加整潔的代碼并提高了 MyBatis 的可用性。

命名解析:為了減少輸入量,MyBatis 對所有的命名配置元素(包括語句,結(jié)果映射,緩存等)使用了如下的命名解析規(guī)則。

  • 完全限定名(比如"com.mypackage.MyMapper.selectAllThings")將被直接查找并且找到即用。
  • 短名稱(比如"selectAllThings")如果全局唯一也可以作為一個單獨的引用。如果不唯一,有兩個或兩個以上的相同名稱(比如"com.foo.selectAllThings "和"com.bar.selectAllThings"),那么使用時就會收到錯誤報告說短名稱是不唯一的,這種情況下就必須使用完全限定名。

對于像 BlogMapper 這樣的映射器類(Mapper class)來說,還有另一招來處理。它們的映射的語句可以不需要用 XML 來做,取而代之的是可以使用 Java 注解。比如,上面的 XML 示例可被替換如下:

    package org.mybatis.example;
    public interface BlogMapper {
      @Select("SELECT * FROM blog WHERE id = #{id}")
      Blog selectBlog(int id);
    }

對于簡單語句來說,注解使代碼顯得更加簡潔,然而 Java 注解對于稍微復(fù)雜的語句就會力不從心并且會顯得更加混亂。因此,如果你需要做很復(fù)雜的事情,那么最好使用 XML 來映射語句。

選擇何種方式以及映射語句的定義的一致性對你來說有多重要這些完全取決于你和你的團隊。換句話說,永遠(yuǎn)不要拘泥于一種方式,你可以很輕松的在基于注解和 XML 的語句映射方式間自由移植和切換。

范圍(Scope)和生命周期

理解我們目前已經(jīng)討論過的不同范圍和生命周期類是至關(guān)重要的,因為錯誤的使用會導(dǎo)致非常嚴(yán)重的并發(fā)問題。

提示 對象生命周期和依賴注入框架

依賴注入框架可以創(chuàng)建線程安全的、基于事務(wù)的 SqlSession 和映射器(mapper)并將它們直接注入到你的 bean 中,因此可以直接忽略它們的生命周期。如果對如何通過依賴注入框架來使用 MyBatis 感興趣可以研究一下 MyBatis-Spring 或 MyBatis-Guice 兩個子項目。

SqlSessionFactoryBuilder

這個類可以被實例化、使用和丟棄,一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 實例的最佳范圍是方法范圍(也就是局部方法變量)。你可以重用 SqlSessionFactoryBuilder 來創(chuàng)建多個 SqlSessionFactory 實例,但是最好還是不要讓其一直存在以保證所有的 XML 解析資源開放給更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運行期間一直存在,沒有任何理由對它進行清除或重建。使用 SqlSessionFactory 的最佳實踐是在應(yīng)用運行期間不要重復(fù)創(chuàng)建多次,多次重建 SqlSessionFactory 被視為一種代碼"壞味道(bad smell)"。因此 SqlSessionFactory 的最佳范圍是應(yīng)用范圍。有很多方法可以做到,最簡單的就是使用單例模式或者靜態(tài)單例模式。

SqlSession

每個線程都應(yīng)該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的范圍是請求或方法范圍。絕對不能將 SqlSession 實例的引用放在一個類的靜態(tài)域,甚至一個類的實例變量也不行。也絕不能將 SqlSession 實例的引用放在任何類型的管理范圍中,比如 Serlvet 架構(gòu)中的 HttpSession。如果你現(xiàn)在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP 請求對象相似的范圍中。換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應(yīng),就關(guān)閉它。這個關(guān)閉操作是很重要的,你應(yīng)該把這個關(guān)閉操作放到 finally 塊中以確保每次都能執(zhí)行關(guān)閉。下面的示例就是一個確保 SqlSession 關(guān)閉的標(biāo)準(zhǔn)模式:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      // do work
    } finally {
      session.close();
    }

在你的所有的代碼中一致性地使用這種模式來保證所有數(shù)據(jù)庫資源都能被正確地關(guān)閉。

映射器實例(Mapper Instances)

映射器是創(chuàng)建用來綁定映射語句的接口。映射器接口的實例是從 SqlSession 中獲得的。因此從技術(shù)層面講,映射器實例的最大范圍是和 SqlSession 相同的,因為它們都是從 SqlSession 里被請求的。盡管如此,映射器實例的最佳范圍是方法范圍。也就是說,映射器實例應(yīng)該在調(diào)用它們的方法中被請求,用過之后即可廢棄。并不需要顯式地關(guān)閉映射器實例,盡管在整個請求范圍(request scope)保持映射器實例也不會有什么問題,但是很快你會發(fā)現(xiàn),像 SqlSession 一樣,在這個范圍上管理太多的資源的話會難于控制。所以要保持簡單,最好把映射器放在方法范圍(method scope)內(nèi)。下面的示例就展示了這個實踐:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      BlogMapper mapper = session.getMapper(BlogMapper.class);
      // do work
    } finally {
      session.close();
    }
上一篇:動態(tài) SQL