3-訓練模型
三、優化 Mybatis 配置
我們已經在之前的學習中,學會了如何編寫一個簡單的 Mybatis 專案。很顯然這還遠遠沒有正真瞭解 Mybatis。我們從 Mybatis 核心配置檔案 mybatis-config 開始優化我們的專案。
3.1 屬性(properties)
在核心配置檔案中 properties 是一個很重要的標籤。它為 XML 提供外來配置,可以進行動態替換,其中最重要的就在於連線資料庫字串的配置。我們在 resources 資料夾下新建一個 db.properties 檔案:
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/kimari?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username=root password=123456
在這之後只需要在 XML 中新增一個 properties 標籤,我們就可以簡化我們的 XML 檔案程式碼了:
<properties resource="db.properties"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
如果一個屬性在不只一個地方進行了配置,那麼,MyBatis 將按照下面的順序來載入:
- 首先讀取在 properties 元素體內指定的屬性。
- 然後根據 properties 元素中的 resource 屬性讀取類路徑下屬性檔案,或根據 url 屬性指定的路徑讀取屬性檔案,並覆蓋之前讀取過的同名屬性。
- 最後讀取作為方法引數傳遞的屬性,並覆蓋之前讀取過的同名屬性。
因此,通過方法引數傳遞的屬性具有最高優先順序,resource/url 屬性中指定的配置檔案次之,最低優先順序的則是 properties 元素中指定的屬性。
3.2 類型別名(typeAliases)
類型別名可為 Java 型別設定一個縮寫名字。 它僅用於 XML 配置,意在降低冗餘的全限定類名書寫。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
當然你還可以直接掃描一個包來給這個包裡所有的類設定類型別名:
<typeAliases>
<package name="com.kimari.pojo"/>
</typeAliases>
下面是一些為常見的 Java 型別內建的類型別名。它們都是不區分大小寫的,注意,為了應對原始型別的命名重複,採取了特殊的命名風格。
別名 | 對映的型別 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
除了用 XML 配置別名,你還可以選擇用 @Alias
註解來設定別名:
@Alias("author")
public class Author {
...
}
3.3 設定(settings)
這是 MyBatis 中極為重要的調整設定,它們會改變 MyBatis 的執行時行為。 下面是重要的幾種屬性:
-
cacheEnabled
全域性性地開啟或關閉所有對映器配置檔案中已配置的任何快取。預設是 true
-
lazyLoadingEnabled
延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。 特定關聯關係中可通過設定
fetchType
屬性來覆蓋該項的開關狀態。預設是 false -
mapUnderscoreToCamelCase
是否開啟駝峰命名自動對映,即從經典資料庫列名 A_COLUMN 對映到經典 Java 屬性名 aColumn。預設是 False
-
logImpl
指定 MyBatis 所用日誌的具體實現,未指定時將自動查詢。可以選擇 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
其中 STDOUT_LOGGING 是標準日誌輸出,它不需要其他依賴,直接就能輸出。
需要注意的是標籤間的順序都是確定的,不能隨意修改。
3.4 環境配置(environments)
MyBatis 可以配置成適應多種環境,這種機制有助於將 SQL 對映應用於多種資料庫之中, 現實情況下有多種理由需要這麼做。例如,開發、測試和生產環境需要有不同的配置;或者想在具有相同 Schema 的多個生產資料庫中使用相同的 SQL 對映。還有許多類似的使用場景。
不過要記住:儘管可以配置多個環境,但每個 SqlSessionFactory 例項只能選擇一種環境。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<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>
事務管理器(transactionManager)
在 MyBatis 中有兩種型別的事務管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 這個配置直接使用了 JDBC 的提交和回滾設施,它依賴從資料來源獲得的連線來管理事務作用域。
- MANAGED – 這個配置幾乎沒做什麼。它從不提交或回滾一個連線,而是讓容器來管理事務的整個生命週期(比如 JEE 應用伺服器的上下文)。 預設情況下它會關閉連線。然而一些容器並不希望連線被關閉,因此需要將 closeConnection 屬性設定為 false 來阻止預設的關閉行為。
資料來源(dataSource)
dataSource 元素使用標準的 JDBC 資料來源介面來配置 JDBC 連線物件的資源。
有三種內建的資料來源型別(也就是 type="[UNPOOLED|POOLED|JNDI]"):
-
UNPOOLED– 這個資料來源的實現會每次請求時開啟和關閉連線。雖然有點慢,但對那些資料庫連線可用性要求不高的簡單應用程式來說,是一個很好的選擇。 效能表現則依賴於使用的資料庫,對某些資料庫來說,使用連線池並不重要,這個配置就很適合這種情形。
-
POOLED– 這種資料來源的實現利用“池”的概念將 JDBC 連線物件組織起來,避免了建立新的連線例項時所必需的初始化和認證時間。 這種處理方式很流行,能使併發 Web 應用快速響應請求。
-
JNDI – 這個資料來源實現是為了能在如 EJB 或應用伺服器這類容器中使用,容器可以集中或在外部配置資料來源,然後放置一個 JNDI 上下文的資料來源引用。
3.5 對映器(mappers)
既然 MyBatis 的行為已經由上述元素配置完了,我們現在就要來定義 SQL 對映語句了。 但首先,我們需要告訴 MyBatis 到哪裡去找到這些語句。 在自動查詢資源方面,Java 並沒有提供一個很好的解決方案,所以最好的辦法是直接告訴 MyBatis 到哪裡去找對映檔案。 你可以使用相對於類路徑的資源引用,或完全限定資源定位符(包括 file:///
形式的 URL),或類名和包名等。例如:
<!-- 使用相對於類路徑的資源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用對映器介面實現類的完全限定類名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 將包內的對映器介面實現全部註冊為對映器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意如果使用類名和包名,介面和他的 Mapper 配置檔案必須同名且必須在同一包下。
四、實現增刪改查
MyBatis 的真正強大在於它的語句對映,這是它的魔力所在。由於它的異常強大,對映器的 XML 檔案就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 程式碼進行對比,你會立即發現省掉了將近 95% 的程式碼。MyBatis 致力於減少使用成本,讓使用者能更專注於 SQL 程式碼。
4.1 select
一個簡單查詢的 select 元素是非常簡單的。比如:
<select id="getUserById" parameterType="_int" resultType="user">
select *
from kimari.user
where id = #{id};
</select>
這個語句名為 getUserById,接收一個 int 型別的引數,並返回一個 User 型別的物件(由於前面已經介紹了別名,我們將省略全限命名)。先介紹幾個比較重要的屬性:
id
:在名稱空間中唯一的識別符號,可以被用來引用這條語句。parameterType
:將會傳入這條語句的引數的類全限定名或別名。這個屬性是可選的,因為 MyBatis 可以通過型別處理器(TypeHandler)推斷出具體傳入語句的引數,預設值為未設定(unset)。resultType
:期望從這條語句中返回結果的類全限定名或別名。 注意,如果返回的是集合,那應該設定為集合包含的型別,而不是集合本身的型別。 resultType 和 resultMap 之間只能同時使用一個。resultMap
:對外部 resultMap 的命名引用。結果對映是 MyBatis 最強大的特性,如果你對其理解透徹,許多複雜的對映問題都能迎刃而解。 resultType 和 resultMap 之間只能同時使用一個。
如果引數型別是基礎型別,則可以省略不寫。
4.2 insert, update 和 delete
資料變更語句 insert,update 和 delete 的實現非常接近:
<insert id="addUser" parameterType="user">
insert into kimari.user(id, name, pwd)
values (#{id}, #{name}, #{pwd});
</insert>
<update id="updateUser" parameterType="user">
update kimari.user
set name = #{name},
pwd = #{pwd}
where id = #{id};
</update>
<delete id="deleteUser">
delete
from kimari.user
where id = #{id};
</delete>
下面是比較重要的屬性:
id
:在名稱空間中唯一的識別符號,可以被用來引用這條語句。parameterType
:將會傳入這條語句的引數的類全限定名或別名。這個屬性是可選的,因為 MyBatis 可以通過型別處理器(TypeHandler)推斷出具體傳入語句的引數,預設值為未設定(unset)。
請注意:這三個語句並沒有 resultMap 和 resultType 屬性。