1. 程式人生 > >Spring Boot 整合 MyBatis(四)

Spring Boot 整合 MyBatis(四)

Spring Boot 整合 MyBatis

    A、ORM框架是什麼?
            物件關係對映(Object Relational Mapping,簡稱 ORM)模式是一種為了解決面向物件與關係資料庫存在的
            互不匹配的現象技術。簡單的說,ORM 是通過使用描述物件和資料庫之間對映的元資料,將程式中的物件自
            動持久化到關係資料庫中。
    
    B、為什麼需要ORM框架
            當開發一個應用程式的時候(不使用 O/R Mapping),可能會寫不少資料訪問層的程式碼,用來從資料庫儲存、
            刪除、讀取物件資訊等。在 DAL 中寫了很多的方法來讀取物件資料、改變狀態物件等任務,而這些程式碼寫
            起來總是重複的。針對這些問題 ORM 提供瞭解決方案,簡化了將程式中的物件持久化到關係資料庫中的操作。
            
            ORM 框架的本質是簡化程式設計中操作資料庫的編碼,一個是宣稱可以不用寫一句 SQL 的 Hibernate,
            一個是以動態 SQL 見長的 MyBatis,兩者各有特點。在企業級系統開發中可以根據需求靈活使用,
            有趣的現象:傳統企業大都喜歡使用 Hibernate,而網際網路行業通常使用MyBatis。
    C、MyBatis 介紹
            MyBatis 支援普通 SQL 查詢,儲存過程和高階對映的優秀持久層框架。MyBatis 消除了幾乎所有的 JDBC 代
            碼和引數的手工設定以及對結果集的檢索封裝。MaBatis 可以使用簡單的 XML 或註解用於配置和原始對映。
            將介面和 Java 的 POJO(Plain Old Java Objects,普通的 Java 物件)對映成資料庫中的記錄。
            
            優點:
                SQL 被統一提取出來,便於統一管理和優化
                SQL 和程式碼解耦,將業務邏輯和資料訪問邏輯分離,使系統的設計更清晰,更易維護,更易單元測試
                提供對映標籤,支援物件與資料庫的 ORM 欄位關係對映
                提供物件關係對映標籤,支援物件關係元件維護
                靈活書寫動態 SQL,支援各種條件來動態生成不同的 SQL
            缺點:
                編寫 SQL 語句時工作量很大,尤其是欄位多、關聯表多時,更是如此
                SQL 語句依賴於資料庫,導致資料庫移植性差

    E、MyBatis 重要的概念
            Mapper 配置: Mapper 配置可以使用基於 XML 的 Mapper 配置⽂檔案來實現,也可以使用基於 Java 註解的
                          MyBatis 註解來實現,甚至可以直接使用 MyBatis 提供的 API 來實現。
            Mapper 介面: Mapper 介面是指自行定義的一個數據操做介面,類似於通常所說的 DAO 接⼝口。早期的Mapper
                          介面需要自定義去實現,現在 MyBatis 會自動為 Mapper 介面建立動態代理物件。Mapper 接
                          口的方法通常與 Mapper 配置⽂檔案中的 select、insert、update、delete 等 XML 結點存在
                          一一對應關係。
            Executor: MyBatis 中所有的 Mapper 語句的執行都是通過 Executor 進行的,Executor 是 MyBatis 的一個
                       核⼼心介面。
            SqlSession: SqlSession 是 MyBatis 的關鍵物件,是執行持久化操作的獨享,類似於 JDBC 中的Connection,
                         SqlSession 物件完全包含以資料庫為背景的所有執行 SQL 操作的方法,它的底層封裝了JDBC連
                         接,可以用 SqlSession 例項來直接執行被對映的 SQL 語句。
            SqlSessionFactory: SqlSessionFactory 是 MyBatis 的關鍵物件,它是單個數據庫對映關係經過編譯後的內
                                存映象。SqlSessionFactory 物件的例項可以通過 SqlSessionFactoryBuilder 物件類獲
                                得,而SqlSessionFactoryBuilder 則可以從 XML 配置檔案或一個預先定製的 
                                Configuration 的例項構建出。

    F、MyBatis 的工作流程如下:
            a、首先載入 Mapper 配置的 SQL 對映檔案,或者是註解的相關 SQL 內容。
            b、建立會話工廠,MyBatis 通過讀取配置檔案的資訊來構造出會話工廠(SqlSessionFactory)。
            c、建立會話。根據會話工廠,MyBatis 就可以通過它來建立會話物件(SqlSession)。會話物件是一個接
               口,該介面中包含了對資料庫操作的增刪改查⽅方法。
            d、建立執行器。因為會話物件本身不能直接操作資料庫,所以它使用了一個叫做資料庫執行器(Executor)
               的介面來幫它執行操作。
            e、封裝 SQL 物件。在這一步,執行器將待處理的 SQL 資訊封裝到一個物件中(MappedStatement),該對
               象包括 SQL 語句、輸⼊入引數對映資訊(Java 簡單型別、HashMap 或 POJO)和輸出結果對映資訊(Java 簡單型別、HashMap 或 POJO)。
            f、操作資料庫。擁有了執行器和 SQL 資訊封裝物件就使用它們訪問資料庫了,最後再返回操作結果,結束流程。
               在具體的使用過程中,按照上述的流程來執行。

1、mybatis-spring-boot-starter 主要提供了兩種解決方式,①XML配置,②使用註解。

A、XML版本

XML 版本保持對映檔案的老傳統,優化主要體現在不需要實現 Dao 的實現層,系統會自動根據方法名在對映檔案中找到對應的 SQL。

POM.XML檔案
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>

    我還會引入另外一個元件,Apache 的 commons-lang 3 ,此包有非常多的工具類可以使用,
    比如常用的判斷字串是否為空,快速複寫實體類的 toString() 方法等。

實體類檔案:UserEntity
    public class UserEntity implements Serializable {

        private static final long serialVersionUID = 1L;
        private Long id;
        private String userName;
        private String passWord;
        private UserSexEnum userSex;
        private String nickName;
        //getter/setter省略
    }
列舉類:
    public enum UserSexEnum {
        MAN, WOMAN
    }

application.properties檔案
    mybatis.config-location=classpath:mybatis/mybatis-config.xml
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
    mybatis.type-aliases-package=com.kid.entity
    
    spring.datasource.driverClassName = com.mysql.jdbc.Driver
    spring.datasource.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
    spring.datasource.username = root
    spring.datasource.password = root

    # mybatis.config-locations :配置 mybatis-config.xml 路徑,mybatis-config.xml 中配置MyBatis 基礎屬性。
    # mybatis.mapper-locations :配置 Mapper 對應的 XML 檔案路徑
    # mybatis.type-aliases-package :配置專案中實體類包路徑
    # spring.datasource.* :資料來源配置
    
    # Spring Boot 啟動時資料來源會自動注入到 SqlSessionFactory 中,使用 SqlSessionFactory 構建
    # SqlSessionFactory,再自動注入到 Mapper 中,最後我們直接使用 Mapper 即可

啟動類:在啟動類中新增對 Mapper 包掃描 @MapperScan ,Spring Boot 啟動的時候會自動載入包路徑下的Mapper。
    @SpringBootApplication
    @MapperScan("com.kid.mapper")
    public class SpringbootMybatisApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootMybatisApplication.class, args);
        }
    }
    
開發SQL:
    MyBatis公共屬性
        <!--配置別名-->
        <typeAliases>
            <typeAlias alias="Integer" type="java.lang.Integer" />
            <typeAlias alias="Long" type="java.lang.Long" />
            <typeAlias alias="HashMap" type="java.util.HashMap" />
            <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
            <typeAlias alias="ArrayList" type="java.util.ArrayList" />
            <typeAlias alias="LinkedList" type="java.util.LinkedList" />
        </typeAliases>
        mybatis-config.xml ,主要配置常用的 typeAliases,設定類型別名為 Java 型別設定一個短的名字。只和 XML 配置有關,存在的意義僅在於用來減少類完全限定名的冗餘。

UserMapper介面
    public interface UserMapper {       
        List<UserEntity> getAll();      
        UserEntity getOne(Long id);     
        void insert(UserEntity user);       
        void update(UserEntity user);       
        int delete(Long id);        
        List<UserEntity> getList(UserParam userParam);      
        Long getCount(UserParam userParam);
    }
    注意:這裡的方法名需要和 XML 配置中的 id 屬性一致,不然會找不到方法去對應執行的 SQL。
    
新增UserMapper對映檔案
    <!--指明對應檔案的 Mapper 類地址-->
    <mapper namespace="com.kid.mapper.UserMapper" >
    
        <!--
            配置表結構和類的對應關係:
                這裡故意將類的兩個欄位和資料庫欄位設定為不一致,並且有一個使用列舉。
                使⽤用列舉有一個非常⼤大的優點,插⼊入此屬性的資料會自動進⾏行校驗,
                如果不是列舉的內容會報錯。
        -->
        <resultMap id="BaseResultMap" type="com.kid.entity.UserEntity" >
            <id column="id" property="id" jdbcType="BIGINT" />
            <result column="userName" property="userName" jdbcType="VARCHAR" />
            <result column="passWord" property="passWord" jdbcType="VARCHAR" />
            <result column="user_sex" property="userSex" javaType="com.kid.enums.UserSexEnum"/>
            <result column="nick_name" property="nickName" jdbcType="VARCHAR" />
        </resultMap>
        
        <sql id="Base_Column_List" >
            id, userName, passWord, user_sex, nick_name
        </sql>
    
        <sql id="Base_Where_List">
            <if test="userName != null  and userName != ''">
                and userName = #{userName}
            </if>
            <if test="userSex != null and userSex != ''">
                and user_sex = #{userSex}
            </if>
        </sql>
    
        <select id="getAll" resultMap="BaseResultMap"  >
           SELECT 
           <include refid="Base_Column_List" />
           FROM users
        </select>
    
        <select id="getList" resultMap="BaseResultMap" parameterType="com.kid.param.UserParam">
            select
            <include refid="Base_Column_List" />
            from users
            where 1=1
            <include refid="Base_Where_List" />
            order by id desc
            limit #{beginLine} , #{pageSize}
        </select>
    
        <select id="getCount" resultType="Integer" parameterType="com.kid.param.UserParam">
            select
            count(1)
            from users
            where 1=1
            <include refid="Base_Where_List" />
        </select>
    
        <select id="getOne" parameterType="Long" resultMap="BaseResultMap" >
            SELECT 
           <include refid="Base_Column_List" />
           FROM users
           WHERE id = #{id}
        </select>
    
        <insert id="insert" parameterType="com.kid.entity.UserEntity" >
           INSERT INTO 
                users
                (userName,passWord,user_sex) 
            VALUES
                (#{userName}, #{passWord}, #{userSex})
        </insert>
        
        <update id="update" parameterType="com.kid.entity.UserEntity" >
           UPDATE 
                users 
           SET 
            <if test="userName != null">userName = #{userName},</if>
            <if test="passWord != null">passWord = #{passWord},</if>
            nick_name = #{nickName}
           WHERE 
                id = #{id}
        </update>
        
        <delete id="delete" parameterType="Long" >
           DELETE FROM
                 users 
           WHERE 
                 id =#{id}
        </delete>
    </mapper>