Mybatis原始碼解析2—— 例項搭建

YSOcean發表於2021-08-17

  大家好,我是可樂。

  上篇文章給大家擼了一遍用 JDBC 直接運算元據庫的例項,還只是簡單寫了一個查詢的介面,其程式碼量就已經很大了,並且可樂還給大家分析了直接使用 JDBC 帶來的一些問題,總之是一種反人類的操作,為了讓這種操作人類正常化,我們選擇使用 ORM 框架。

  本篇文章給大家從頭搭建一遍,如何基於 XML 配置,使用 Mybatis 進行增刪改查操作。

  看到這,可能有讀者就要問了,what?

  

 

 

 

  我現在使用 Springboot 多爽,還要這些複雜的配置幹啥?

  可樂這裡要說的是,Springboot 用起來是爽,它啥都給你封裝好了,但是很多細節問題你可能並不知道,後續擼 Mybatis 的原始碼流程也是基於此,所以大家一定要過一遍 Mybatis 原始的執行方式。

  專案原始碼地址:https://github.com/YSOcean/mybatisproject

  這裡可樂不會介紹各種配置含義,需要的可以直接參考官網,更加權威,你值得擁有:https://mybatis.org/mybatis-3/zh/configuration.html

1、建立庫表

  以 Mysql 資料庫為例,表比較簡單,這裡可樂就直接放圖和建表語句了。

-- ----------------------------
-- Table structure for person
-- ----------------------------
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
  `pid` int NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `page` int DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
​
-- ----------------------------
-- Records of person
-- ----------------------------
BEGIN;
INSERT INTO `person` VALUES (1, 'itcoke', 11);
INSERT INTO `person` VALUES (2, 'IT可樂', 22);
COMMIT;

  

2、建立工程

  通過 IDEA 建立一個工程,並匯入相應的jar包。

  以 maven 為例,配置 MySQL 和 Mybatis 即可。

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
</dependency>

 

  整個專案結構可以參考我的GitHub地址:https://github.com/YSOcean/mybatisproject

3、建立與表對應的實體類物件

 1 package com.itcoke.bean;
 2  3 public class Person {
 4  5     private Long pid;
 6  7     private String pname;
 8  9     private Integer page;
10 11     public Long getPid() {
12         return pid;
13     }
14 15     public void setPid(Long pid) {
16         this.pid = pid;
17     }
18 19     public String getPname() {
20         return pname;
21     }
22 23     public void setPname(String pname) {
24         this.pname = pname;
25     }
26 27     public Integer getPage() {
28         return page;
29     }
30 31     public void setPage(Integer page) {
32         this.page = page;
33     }
34 35     @Override
36     public String toString() {
37         return "Person{" +
38                 "pid=" + pid +
39                 ", pname='" + pname + '\'' +
40                 ", page=" + page +
41                 '}';
42     }
43 }

4、編寫資料庫配置檔案 mybatis-config.xml

關於配置檔案的詳細介紹,可以參考官網:https://mybatis.org/mybatis-3/zh/configuration.html

<?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><!-- 可以配置多個執行環境,但是每個 SqlSessionFactory 例項只能選擇一個執行環境  -->
    <!-- 預設使用的環境 ID,名字隨意,但是要匹配下面其中一個環境 ID -->
    <environments default="development">
        <!-- 環境ID -->
        <environment id="development">
            <!--事務管理器
                一、JDBC:這個配置直接簡單使用了 JDBC 的提交和回滾設定。它依賴於從資料來源得到的連線來管理事務範圍
                二、MANAGED:這個配置幾乎沒做什麼。它從來不提交或回滾一個連線。而它會讓容器來管理事務的整個生命週期
                    比如 spring 或 JEE 應用伺服器的上下文,預設情況下,它會關閉連線。然而一些容器並不希望這樣,
                    因此如果你需要從連線中停止它,就可以將 closeConnection 屬性設定為 false,比如:
                    <transactionManager type="MANAGED">
                        <property name="closeConnection" value="false"/>
                    </transactionManager>
              -->
            <transactionManager type="JDBC"/>
            <!--dataSource 元素使用標準的 JDBC 資料來源介面來配置 JDBC 連線物件源  -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-study"/>
                <property name="username" value="root"/>
                <property name="password" value="root1234"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

5、定義person表對映檔案

官方權威地址:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

<?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.itcoke.mapper.PersonMapper">
​
​
    <!-- 根據 id 查詢 person 表中的資料
       id:唯一識別符號,此檔案中的id值不能重複
       resultType:返回值型別,一條資料庫記錄也就對應實體類的一個物件
       parameterType:引數型別,也就是查詢條件的型別
    -->
    <select id="selectPersonById"
            resultType="com.itcoke.bean.Person" parameterType="java.lang.Long" >
        <!-- 這裡和普通的sql 查詢語句差不多,後面的 #{id}表示佔位符,裡面不一定要寫id,寫啥都可以,但是不要空著 -->
        select * from person where pid = #{pid}
    </select>
​
​
​
    <!-- 根據 id 更新 person 表的資料 -->
    <update id="updatePersonById" parameterType="com.itcoke.bean.Person">
        update person p
        <trim prefix="set" suffixOverrides=",">
            <if test="pname != null and pname != ''">
                p.pname = #{pname},
            </if>
            <if test="page != null and page != ''">
                p.page = #{page},
            </if>
        </trim>
​
        where pid=#{pid}
    </update>
​
​
    <!-- 向 person 表插入一條資料 -->
    <insert id="insertPerson" parameterType="com.itcoke.bean.Person">
        insert into person(pname,page)
        value(#{pname},#{page})
    </insert>
​
​
​
    <!-- 根據 id 刪除 person 表的資料 -->
    <delete id="deletePersonById" parameterType="Long">
        delete from person where pid=#{pid}
    </delete></mapper>

6、向 mybatis-config.xml 中註冊對映檔案

<mappers>
    <!-- 註冊PersonMapper.xml檔案 -->
    <mapper resource="com/itcoke/mapper/PersonMapper.xml"/>
</mappers>

 

7、編寫測試類

 1 package com.itcoke;
 2  3  4 import com.itcoke.bean.Person;
 5 import com.itcoke.mapper.PersonMapper;
 6 import org.apache.ibatis.io.Resources;
 7 import org.apache.ibatis.session.SqlSession;
 8 import org.apache.ibatis.session.SqlSessionFactory;
 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
10 import org.junit.Before;
11 import org.junit.Test;
12 13 import java.io.IOException;
14 import java.io.InputStream;
15 16 public class MybatisprojectApplicationTests {
17     // 定義SqlSessionFactory
18     SqlSessionFactory sessionFactory = null;
19 20     @Before
21     public void init() {
22         //定義mybatis全域性配置檔案
23         String resource = "mybatis-config.xml";
24         //載入 mybatis 全域性配置檔案
25         InputStream inputStream = null;
26         try {
27             inputStream = Resources.getResourceAsStream(resource);
28         } catch (IOException e) {
29             e.printStackTrace();
30         }
31         //構建sqlSession的工廠
32         sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
33 34     }
35 36     //根據id查詢person表資料
37     @Test
38     public void testSelectPersonById() {
39         /*這個字串由 PersonMapper.xml 檔案中 兩個部分構成
40             <mapper namespace="com.itcoke.mapper.PersonMapper"> 的 namespace 的值
41             <select id="selectPersonById" > id 值
42         */
43         String namespace = "com.itcoke.mapper.PersonMapper";
44         String method = "selectPersonById";
45         //根據 sqlSessionFactory 產生 session
46         SqlSession sqlSession = sessionFactory.openSession();
47         Person person = sqlSession.selectOne(namespace + "." + method, 1L);
48         System.out.println(person);
49         sqlSession.close();
50     }
51 52 53     //根據id更新person表資料
54     @Test
55     public void testUpdatePersonById() {
56         String statement = "com.itcoke.mapper.PersonMapper.updatePersonById";
57         Person p = new Person();
58         p.setPid(2L);
59         p.setPage(18);
60         //根據 sqlSessionFactory 產生 session
61         SqlSession sqlSession = sessionFactory.openSession();
62         sqlSession.update(statement, p);
63         sqlSession.commit();
64         sqlSession.close();
65     }
66 67 68     //向 person 表插入資料
69     @Test
70     public void testInsertPerson() {
71         String statement = "com.itcoke.mapper.PersonMapper.insertPerson";
72         Person p = new Person();
73         p.setPname("可樂");
74         p.setPage(18);
75         //根據 sqlSessionFactory 產生 session
76         SqlSession sqlSession = sessionFactory.openSession();
77         sqlSession.insert(statement, p);
78         sqlSession.commit();
79         sqlSession.close();
80     }
81 82     //根據id更新person表資料
83     @Test
84     public void testDeletePersonById() {
85         String statement = "com.itcoke.mapper.PersonMapper.deletePersonById";
86         Person p = new Person();
87         p.setPid(4L);
88         //根據 sqlSessionFactory 產生 session
89         SqlSession sqlSession = sessionFactory.openSession();
90         sqlSession.delete(statement, p);
91         sqlSession.commit();
92         sqlSession.close();
93     }
94 }

 

9、通過介面

  在上面的例子中,我們發現 statement 每次都要自己書寫拼接,很容易就寫錯了,這時候 MyBatis 提供了介面註冊方式。

  ①、在 mapper 包下面新建一個 PersonMapper 介面

  注意要和 PersonMapper.xml 同名,且在同一個包下,因為要和 namespace 相同。

 1 package com.itcoke.mapper;
 2  3 import com.itcoke.bean.Person;
 4  5  6 public interface PersonMapper {
 7  8     Person selectPersonById(long pid);
 9 10     void updatePersonById(Person person);
11 12     void insertPerson(Person person);
13 14     void deletePersonById(long pid);
15 }

  ②、測試

 1 //根據id查詢person表資料
 2 //通過介面代理的方式
 3 @Test
 4 public void testInterfaceSelectPersonById() {
 5     //根據 sqlSessionFactory 產生 session
 6     SqlSession sqlSession = sessionFactory.openSession();
 7     PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
 8     Person person = mapper.selectPersonById(1L);
 9     System.out.println(person);
10     sqlSession.close();
11 }

8、小結

  至此,我們從頭到尾擼了一遍利用 Mybatis 進行增刪改查,後面便會深入底層,梳理架構。

 

相關文章