什麼是MyBatis
MyBatis 是當前主流的 ORM 框架,是由 Apache 提供的一個開源專案,之前的名字叫做 iBatis,2010 年遷移到了 Google Code,並且將名字改為我們現在所熟知的 MyBatis,又於 2013 年 11 月遷移到了 Github。MyBatis 是一個幫助開發者實現資料持久化工作的框架,它同時支援 Java、.NET、Ruby 三種語言的實現,當然我們這裡講的是在 Java Application 中的使用,初學者可以將 MyBatis 簡單理解為一個對 JDBC 進行封裝的框架。
說到 ORM 框架就不得不提 Hibernate,Hibernate 是實現了 JPA 規範的 ORM 框架,使用非常廣泛,Spring Data JPA 底層就是採用 Hibernate 技術支援。同為 ORM 框架,MyBatis 與 Hibernate 的區別是什麼呢?
Hibernate 是一個“全自動化”的 ORM 框架,而 MyBatis 則是一個“半自動化”的 ORM 框架。
什麼是“全自動化”?意為開發者只需要呼叫相關介面就可以完成操作,整個流程框架都已經封裝好了,開發者無需關注。具體來講 Hibernate 實現了 POJO 和資料庫表之間的對映,同時可以自動生成 SQL 語句並完成執行。
“半自動化”指的是框架只提供了一部分功能,剩下的工作仍需要開發者手動完成,MyBatis 框架沒有實現 POJO 與資料庫表的對映,它只實現了 POJO 與 SQL 之間的對映關係,同時需要開發者手動定義 SQL 語句,以及資料與 POJO 的裝配關係。
雖然功能上沒有 Hibernate 更加方便,但是這種“半自動化”的方式提高了框架的靈活性,MyBatis 對所有的 JDBC 程式碼實現了封裝,包括引數設定、SQL 執行、結果集解析等,透過 XML 配置的方式完成 POJO 與資料的對映。
MyBatis 的優點
- 極大地簡化了 JDBC 程式碼的開發
- 簡單好用、容易上手,具有更好的靈活性
- 透過將 SQL 定義在 XML 檔案中的方式降低呈現的耦合度
- 支援動態 SQL,可根據具體業務靈活實現需求
MyBatis 的缺點
- 相比於 Hibernate,開發者需要完成更多工作,如定義 SQL、設定 POJO 與資料的對映關係等
- 要求開發人員具備一定的 SQL 編寫能力,在一些特定場景下工作量較大
- 資料庫移植性較差,因為 SQL 依賴於底層資料庫,如果要進行資料庫遷移,部分 SQL 需要重新編寫
整體來說,MyBatis 是一個非常不錯的持久層解決方案,它專注於 SQL 本身,非常靈活,適用於需求變化較多的網際網路專案,也是當前主流的 ORM 框架。
MyBatis 快速入門
(1)建立 Maven 工程,pom.xml 新增相關依賴,我們使用 MySQL 資料庫,因此需要額外引入 MySQL 驅動依賴。為了在控制檯上顯示SQL語句,還需要引入log4j依賴。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
在resources目錄下新建log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<!-- 將日誌資訊輸出到控制檯 -->
<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<!-- 設定日誌輸出的樣式 -->
<layout class="org.apache.log4j.PatternLayout">
<!-- 設定日誌輸出的格式 -->
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss:SSS}] %m%n" />
</layout>
<!--過濾器設定輸出的級別-->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<!-- 設定日誌輸出的最小級別 -->
<param name="levelMin" value="DEBUG" />
<!-- 設定日誌輸出的最大級別 -->
<param name="levelMax" value="ERROR" />
<!-- 設定日誌輸出的xxx,預設是false -->
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<!-- 根logger的設定-->
<root>
<appender-ref ref="ConsoleAppender"/>
</root>
</log4j:configuration>
(2)新建資料表
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(255) DEFAULT NULL,
user_email varchar(255) DEFAULT NULL,
user_city varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
PRIMARY KEY (id)
)
(3)建立user表對應的實體類
public class User {
private Integer id;
private String username;
private String userEmail;
private String userCity;
private Integer age;
// 省略get、set方法
}
(4)在 resources 路徑下建立 MyBatis 配置檔案mybatis- config.xml(檔名可自定義),配置資料來源資訊。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<!-- 配置 MyBatis 執行環境 -->
<environment id="development">
<!-- 配置 JDBC 事務管理 -->
<transactionManager type="JDBC"/>
<!-- POOLED 配置 JDBC 資料來源連線池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
(5)MyBatis 開發有兩種方式:
- 使用原生介面
- Mapper 代理實現自定義介面
先來說第一種使用原生介面的開發方式。
第一步,在resources目錄下建立mapper資料夾,並建立 UserMapper.xml。
<?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">
<!--
namespace: 名稱空間, 如果有對應的介面,需要指定為對應介面的全類名, 如果使用原生介面, 則可以隨便填寫
id: 唯一標識
parameterType: 為引數資料型別,可以省略
resultType: 為返回值資料型別
#{username}是獲取傳遞過來的引數中獲取 username 的值
-->
<mapper namespace="com.example.mybatis.mapper.UserMapper">
<select id="getUserByUserName"
parameterType="java.util.String"
resultType="com.example.mybatis.entity.User">
select
id,
username,
user_email userEmail,
user_city userCity,
age
from user
where username = #{username}
</select>
</mapper>
第二步,在全域性配置檔案 mybatis-config.xml 中註冊 UseMapper.xml。
<configuration>
<environments default="development">
<!-- 配置 MyBatis 執行環境 -->
<environment id="development">
<!-- 配置 JDBC 事務管理 -->
<transactionManager type="JDBC"/>
<!-- POOLED 配置 JDBC 資料來源連線池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 註冊UserMapper.xml -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
第三步,在測試類中呼叫原生介面執行 SQL 語句獲取結果。
public class App1 {
public static void main( String[] args ) {
// 載入 MyBatis 配置檔案
InputStream is = App1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 獲取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 呼叫 MyBatis 原生介面執行 SQL
// statement 為 UserMapper.xml 的 namespace 值+"."+select 標籤的 id 值
String statement = "com.example.mybatis.mapper.UserMapper.getUserByUserName";
User user = sqlSession.selectOne(statement , "zhangsan");
// SqlSession的selectOne(String var1, Object var2)方法
// 可以發現第二個引數是Object型別的,
// 例子中我們只傳遞了一個引數, 如果想傳入多個引數的話, 可以傳遞一個Map或者是一個實體類物件
System.out.println(user);
}
}
我們在實際開發中,推薦使用第二種方式:自定義介面,但是開發者不需要實現該介面,只需要定義即可,具體的實現工作由 Mapper 代理結合配置檔案完成,實現邏輯或者說要執行的 SQL 語句配置在 Mapper.xml 中。
第一步,自定義介面
public interface UserMapper {
public User getUserByUserName(String userName);
public List<User> getUserList();
public int addUser(User user);
public int deleteUser(Integer id);
public int updateUser(User user);
}
第二步, 將UserMapper.xml中的namespace設定為UserMapper的全類名
<?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">
<!--
namespace: 名稱空間, 如果有對應的介面,需要指定為對應介面的全類名, 如果使用原生介面, 則可以隨便填寫
id: 唯一標識
parameterType: 為引數資料型別,可以省略
resultType: 為返回值資料型別
#{username}是獲取傳遞過來的引數中獲取 username 的值
-->
<mapper namespace="com.example.mybatis.mapper.UserMapper">
<select id="getUserByUserName"
parameterType="String"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
where username = #{username}
</select>
<select id="getUserList"
resultType="com.example.mybatis.entity.User">
select
id, username, user_email userEmail, user_city userCity, age
from user
</select>
<insert id="addUser"
parameterType="com.example.mybatis.entity.User">
insert into user
(username, user_email, user_city, age)
values (#{username}, #{userEmail}, #{userCity}, #{age})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="com.example.mybatis.entity.User">
update user
set username=#{username}, user_email=#{userEmail}, user_city=#{userCity}, age=#{age}
where id=#{id}
</update>
</mapper>
UserMapper.xml 中 namespace 為介面的全類名
UserMapper.xml 中的 id 為介面中對應的方法名
UserMapper.xml 中的 parameterType 和介面中對應方法的引數型別一致
UserMapper.xml 中的 resultType 和介面中對應方法的返回值型別一致
第四步,測試。
public class App2 {
public static void main( String[] args ) {
// 載入 MyBatis 配置檔案
InputStream is = App2.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 獲取 SqlSession, 代表和資料庫的一次會話, 用完需要關閉
// SqlSession 和Connection, 都是非執行緒安全的, 每次使用都應該去獲取新的物件
SqlSession sqlSession = sqlSessionFactory.openSession();
// 獲取實現介面的代理物件
// UserMapper 並沒有實現類, 但是mybatis會為這個介面生成一個代理物件(將介面和xml繫結)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 1. 查詢
User user = userMapper.getUserByUserName("zhangsan");
System.out.println(user.toString());
List<User> userList = userMapper.getUserList();
userList.stream().forEach(obj -> System.out.println(obj.toString()));
/*-------------------------------------------------------------------*/
// 2. 新增
User addUser = new User();
addUser.setUsername("lzc");
addUser.setUserEmail("lzc@qq.com");
addUser.setUserCity("深圳");
addUser.setAge(18);
userMapper.addUser(addUser);
sqlSession.commit(); // 提交事務
/*-------------------------------------------------------------------*/
// 3. 刪除
userMapper.deleteUser(1);
sqlSession.commit(); // 提交事務
/*-------------------------------------------------------------------*/
// 4. 修改
User updateUser = new User();
updateUser.setId(4);
updateUser.setUsername("lizhencheng");
updateUser.setUserEmail("lizhencheng@qq.com");
updateUser.setUserCity("桂林");
updateUser.setAge(16);
userMapper.updateUser(updateUser);
sqlSession.commit(); // 提交事務
/*-------------------------------------------------------------------*/
sqlSession.close();
}
}
程式碼連結:https://github.com/923226145/MyBatis-learn...
本作品採用《CC 協議》,轉載必須註明作者和本文連結