MyBatis mapper
1. 前言
本小節(jié),我們將一起學(xué)習(xí) MyBatis mapper。
在上一節(jié)中我們以 JDBC 的方式使用了 MyBatis,但在實際應(yīng)用中是不會選擇這種方式來執(zhí)行 SQL 的,MyBatis提供了 mapper 這種優(yōu)雅且易維護
的方式來幫助我們更好地去使用 SQL。
2. 定義
慕課解釋:mapper 是 Java 方法和 SQL 語句之間的
橋梁
。
Java 接口方法與 SQL 語句以及 mapper 之間的關(guān)系如下圖所示:
3. 新建 mapper
mapper 只是一個抽象的概念
,它其實就是 Java 里面的一個接口類,我們不需要實現(xiàn)這個接口類,MyBatis 會通過動態(tài)代理自動幫我們執(zhí)行接口方法所對應(yīng)的 SQL 語句。
接下來,我們以UserMapper
為例,來看一看 mapper 究竟是如何定義和組成的。
首先,在 com.imooc.mybatis 包下新建 mapper
包,并在 mapper 包下新建接口類UserMapper.java
。如下:
package com.imooc.mybatis.mapper;
public interface UserMapper {
}
MyBatis 提供了注解
和XML
兩種方式來連接接口方法和 SQL 語句。
3.1 注解方式
我們?yōu)?UserMapper 添加一個方法selectUsernameById
,該方法的作用為通過用戶 id 查詢用戶名稱,如下:
package com.imooc.mybatis.mapper;
public interface UserMapper {
String selectUsernameById(Integer id);
}
selectUsernameById 方法接受 id 參數(shù)(用戶 id),返回用戶名稱(String 類型)。
有了方法定義后,我們再通過注解為該方法添加上對應(yīng)的 SQL 語句:
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT username FROM imooc_user WHERE id = #{id}")
String selectUsernameById(Integer id);
}
Select
注解對應(yīng) SQL 的 select 查詢,注解中的語句就是相應(yīng)的 SQL 語句,當(dāng)然這并非真實的 SQL 語句,具體的差異性我們后續(xù)章節(jié)再說。
3.2 XML 方式
XML 方式是更加強大和易用的一種方式,雖然它沒有注解那么方便,但是功能更強、更易維護,是 MyBatis 官方推薦的一種方式。
在 mapper 包中,我們新建另一個文件UserMapper.xml
,并添加如下內(nèi)容:
<?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.imooc.mybatis.mapper.UserMapper">
</mapper>
mapper
標簽對應(yīng)一個 mapper 接口類,這里應(yīng)該對應(yīng) UserMapper,所以在 mapper 標簽里面我們還需要加上 namespace 這個屬性,它的值為 UserMapper 的類全路徑,這樣 UserMapper.xml 配置文件就與 UserMapper.java 對應(yīng)起來了。
提示,namespace 命名空間是每一個 mapper 文件所獨有的,它唯一標識著一個 mapper。
注意: 在這里,.xml 配置文件必須與其對應(yīng)的接口在同一個包內(nèi)。
二者在目錄中的位置如下:
src/main/java/com/imooc/mybatis/mapper
├── UserMapper.java
└── UserMapper.xml
在 UserMapper 接口中,我們再新增一個方法selectUserAgeById
,該方法的作用是通過用戶 id 查詢用戶年齡。如下:
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT username FROM imooc_user WHERE id = #{id}")
String selectUsernameById(Integer id);
Integer selectUserAgeById(Integer id);
}
與之對應(yīng)的 xml 文件中,我們也需要添加上對應(yīng)的 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.imooc.mybatis.mapper.UserMapper">
<select id="selectUserAgeById" resultType="java.lang.Integer">
SELECT age FROM imooc_user WHERE id = #{id}
</select>
</mapper>
在 mapper 標簽中,我們新增了 select 標簽,對應(yīng) SQL 中的 select 查詢;select 標簽中有兩個必填屬性,第一個是 id ,它對應(yīng)接口的方法名,即 selectUserAgeById,通過它 MyBatis 才能將二者對應(yīng)起來,第二個是 resultType,它對應(yīng) SQL 語句的返回類型,與接口方法的返回值相同,為 Integer 類型。
好了,注解和 XML 的兩種方式的簡單使用已經(jīng)介紹完畢了,這里仍然有一個可以完善的點,我們可以為 UserMapper 類打上一個 Mapper
注解,雖然這個注解并不是必須的,但是增強了代碼的可讀性。如下:
// 省略
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
// 省略其它諸多代碼
}
4. 使用 mapper
mapper 定義好以后,我們接下來會介紹如何使用它。在上一節(jié)中,我們介紹了 MyBatis 配置式的簡單使用,那么使用 mapper 其實很簡單,只需在配置式使用的基礎(chǔ)上增加幾處配置和代碼就行了。
4.1 mapper 配置
首先,我們需要在 mybatis-config.xml 配置文件中添加上對應(yīng)的 mapper 配置:
<?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="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/imooc?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- mapper 對應(yīng)的配置 -->
<mappers>
<mapper class="com.imooc.mybatis.mapper.UserMapper"/>
</mappers>
</configuration>
注意,mapper 可以有多個,對應(yīng)的標簽項應(yīng)是 mappers,在 mappers 下面才有一個個的 mapper,如上面的 UserMapper;通過mapper 標簽中的 class 屬性,我們指定其對應(yīng)的接口類,class 屬性值為 UserMapper 的類全路徑。
4.2 代碼調(diào)用
有了配置以后,我們則可以在代碼中調(diào)用 mapper 方法從而執(zhí)行 SQL 得到結(jié)果了。在 pattern 包下,我們新建一個文件,名為StartWithMapper.java
,并向其中添加如下代碼:
package com.imooc.mybatis.pattern;
import com.imooc.mybatis.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
@SuppressWarnings({"Duplicates"})
public class StartWithMapper {
public static void main(String[] args) throws IOException, SQLException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
// 得到 mapper
UserMapper mapper = session.getMapper(UserMapper.class);
// 調(diào)用注解的SQL
String username = mapper.selectUsernameById(1);
System.out.println("username: " + username);
// 調(diào)用XML的SQL
Integer age = mapper.selectUserAgeById(1);
System.out.println("age: " + age);
// 關(guān)閉會話
session.close();
}
}
使用流程我們已經(jīng)寫在了代碼注釋中了,請務(wù)必閱讀一下。
與上一節(jié)的區(qū)別在于,我們不再通過 session 得到連接從而執(zhí)行 SQL 了,而是在 session 中得到配置好的 UserMapper,再通過調(diào)用UserMapper 的方法執(zhí)行 SQL 從而得到結(jié)果。
執(zhí)行這段代碼,它會在控制臺上打印如下信息(截取了部分重要信息):
13:13:50.104 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - ==> Preparing: SELECT username FROM imooc_user WHERE id = ?
13:13:50.205 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - ==> Parameters: 1(Integer)
13:13:50.344 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - <== Total: 1
username: peter
13:13:50.351 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - ==> Preparing: SELECT age FROM imooc_user WHERE id = ?
13:13:50.351 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - ==> Parameters: 1(Integer)
13:13:50.354 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - <== Total: 1
age: 18
4.3 總結(jié)
從程序輸出的信息中可以看出,UserMapper 的調(diào)用都成功了, 結(jié)合上一小節(jié)中 JDBC 的使用,可以清晰地感受到 MyBatis 完美的將 Java 對象與 SQL 語句分離,并通過 mapper 充當(dāng)二者的橋梁,極大的提升了代碼和 SQL 語句的維護性。
不同于原生 JDBC 的使用方式,MyBatis 會自動的通過 resultType 等配置來幫我們實現(xiàn)數(shù)據(jù)庫類型到 Java 類型的轉(zhuǎn)換,幫我們節(jié)省了大量的工作,當(dāng)然 MyBatis 的功能遠不止如此,我們將在后續(xù)的小節(jié)中一一揭曉。
5. 小結(jié)
- mapper 是 MyBatis 的核心概念,是 MyBatis
解耦
Java 對象與 SQL 語句的橋梁。 - MyBatis 官方文檔中明確
強調(diào)
注解方式 SQL 無法發(fā)揮 MyBatis 的全部功能,但是可以方便地演示一些 demo。 - 如果單獨使用 MyBatis,那么 mapper 接口必須和 .xml 配置文件在同一個包中,但是如果使用 spring 等工具就可以不必受此限制。