MyBatis 入門

LZC發表於2020-02-16

什麼是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&amp;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&amp;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 協議》,轉載必須註明作者和本文連結

相關文章