1. 程式人生 > 程式設計 >【MyBatis-Plus-In-Action】七、外掛拓展

【MyBatis-Plus-In-Action】七、外掛拓展

上一節我們學習了mybatis-plus 的程式碼生成器,這一節我們來學習一下mybatis-plus 的外掛拓展

首先我們來複習一下Mybatis 外掛機制:

  1. 外掛機制: Mybatis 通過外掛(Interceptor) 可以做到攔截四大物件相關方法的執行,根據需求, 完成相關資料的動態改變。 Executor StatementHandler ParameterHandler ResultSetHandler
  2. 外掛原理: 四大物件的每個物件在建立時,都會執行 interceptorChain.pluginAll(),會經過每個外掛物件的 plugin()方法,目的是為當前的四大物件建立代理。代理物件就可以攔截到四大物件相關方法的執行,因為要執行四大物件的方法需要經過代理。

我們在mybatis-plus這裡學習三個外掛,其他的外掛看官可以自己自行嘗試:

  • 分頁外掛
  • 執行分析外掛
  • 樂觀鎖外掛

首先按照快速開始——Spring整合Mybatis-Plus一節的操作,新建一個mp06 的 Module,可以將mp05中的內容全部複製過來。

修改mp06的pom.xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mybatis-plus-in-action</artifactId>
        <groupId>com.demo.mybatis-plus</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mp06</artifactId>

    <dependencies>
        <!-- mp 依賴
            mybatis-plus 會自動維護mybatis 以及 mybatis-spring相關的依賴
            Mybatis 及 Mybatis-Spring 依賴請勿加入專案配置,以免引起版本衝突!!!Mybatis-Plus 會自動幫你維護!
         -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>
        <!--junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <!-- log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--注意: MyBatis-Plus 從 3.0.3 之後移除了程式碼生成器與模板引擎的預設依賴,需要手動新增相關依賴: -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>
        <!--模板引擎
        MP 的程式碼生成器預設使用的是 Apache 的 Velocity 模板,當然也可以更換為別的模板
        技術,例如 freemarker。此處不做過多的介紹。
        需要加入 Apache Velocity 的依賴-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>${velocity.version}</version>
        </dependency>
        <!--加入 slf4j,檢視日誌輸出資訊-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
    </dependencies>
</project>
複製程式碼

下面我們需要根據不同的外掛做的一些修改:

1、分頁外掛

其實在之前的分頁查詢程式碼示例中,我們已經展示了分頁外掛,不過當時並沒有介紹,現在我們來詳細介紹一下。

我們有兩種配置方式可以實現分頁的功能:

1.1、修改mybatis-config.xml檔案,新增分頁外掛

<!-- 1、第一種方式,在 mybatis-config.xml 檔案中引入分頁外掛-->
<plugins>
    <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>
複製程式碼

完整mybatis-config.xml檔案如下:

<?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>

    <!-- 1、第一種方式,在 mybatis-config.xml 檔案中引入分頁外掛-->
    <plugins>
        <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
    </plugins>

</configuration>
複製程式碼

1.2、修改applicationContext.xml檔案,新增分頁外掛

sqlSessionFactory這個bean中,通過<property name="plugins">配置外掛,接下來的所有外掛都配置在這個list中

<!-- 2、第二種方式,在 applicationContext.xml 檔案中引入分頁外掛-->
<property name="plugins">
    <list>
        <!-- 分頁查詢外掛 -->
        <bean id="paginationInterceptor"
              class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
            <property name="dialectType" value="mysql"/>
        </bean>
    </list>
</property>
複製程式碼

1.3、測試分頁外掛

1.1和1.2的方式選擇哪一種都可以實現分頁的功能,現在我們在 TestMp 測試類中新增下面程式碼,來測試分頁外掛的功能

/**
* 測試分頁外掛
*/
@Test
public void testPage() {
    IPage<Employee> employeeIPage = employeeMapper.selectPage(new Page<>(2,1),null);
    System.out.println("employeeIPage:" + employeeIPage.getRecords());
}
複製程式碼

2、執行分析外掛

該外掛的作用是分析 DELETE UPDATE 語句,防止小白或者惡意進行 DELETE UPDATE 全表操作 。在外掛的底層 通過 SQL 語句分析命令:Explain 分析當前的 SQL 語句, 根據結果集中的 Extra 列來斷定當前是否全表操作。

注意:只建議在開發環境中使用,不建議在生產環境使用 。SQL 執行分析攔截器,只支援 MySQL5.6.3 以上版本 。

2.2、修改applicationContext.xml檔案,新增執行分析外掛

 <!-- 執行分析外掛 只建議在開發環境中使用,不建議在生產環境使用 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
    <property name="sqlParserList">
        <!-- 禁止全表刪除-->
        <bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
    </property>
</bean>
複製程式碼

2.2、測試執行分析外掛

我們來進行一個全表刪除來測試一下我們的執行分析外掛,在測試類中新增下面的程式碼:

/**
* 測試 SQL 執行分析外掛
*/
@Test
public void testSqlExplain() {

    // 全表刪除
    employeeMapper.delete(null);
}
複製程式碼

執行該方法後我們會看到測試方法執行失敗,提示我們禁止全表的刪除:

mp06-01.png

3、樂觀鎖外掛

思考?如果想實現如下需求: 當要更新一條記錄的時候,希望這條記錄沒有被別人更新 。當我們想實現上面的需求的時候,首先想到的是使用樂觀鎖機制。

樂觀鎖的實現原理: 1)取出記錄時,獲取當前 version 2)更新時,帶上這個 version 3)執行更新時, set version = yourVersion+1 where version = yourVersion 如果 version 不對,就更新失敗

3.1、修改applicationContext.xml檔案,新增樂觀鎖外掛

要想使用Mybatis-Plus提供的樂觀鎖外掛,首先需要修改applicationContext.xml檔案,新增樂觀鎖外掛

<!-- 樂觀鎖外掛,做這個測試的時候,需要給實體類接一個version欄位,相應的也需要在資料庫中新增該欄位 -->
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
複製程式碼

3.2、修改Employee實體類

修改Employee實體類,新增 version 欄位,並新增getter、setter方法

@Version
private Integer version;

public Integer getVersion() {
    return version;
}

public void setVersion(Integer version) {
    this.version = version;
}
複製程式碼

3.3、測試樂觀鎖外掛

在測試類中新增下面的程式碼:

/**
* 測試 樂觀鎖
*/
@Test
public void testOptimisticLocker() {

    Employee employee = new Employee();
    employee.setId(10);
    employee.setLastName("MP");
    employee.setAge(25);
    employee.setEmail("[email protected]");
    employee.setGender("0");
    employee.setVersion(2);

![mp06-02.png](https://upload-images.jianshu.io/upload_images/19878305-e8348cc75321c5f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    employeeMapper.updateById(employee);
}
複製程式碼

執行該方法後我們會看到測試方法執行成功,更新時,帶上這個 version,但更新的資料為0條,表示資料庫中的資料並沒有被更新,注意看我們的更新程式碼:

mp06-02.png

完成上面的操作後,mp06的完整applicationContext.xml檔案如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring
        http://mybatis.org/schema/mybatis-spring-1.2.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- 資料來源 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource"
          class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!-- 事務管理器 -->
    <bean id="dataSourceTransactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 基於註解的事務管理 -->
    <tx:annotation-driven
            transaction-manager="dataSourceTransactionManager"/>

    <!-- 配置 SqlSessionFactoryBean
        mybatis提供的:org.mybatis.spring.SqlSessionFactoryBean
        mybatis-plus提供的:3.2.0 com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean
                2.3 com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
     -->
    <bean id="sqlSessionFactoryBean"
          class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <!-- 資料來源 -->
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 別名處理 -->
        <property name="typeAliasesPackage" value="com.mp.beans"></property>
        <!-- 注入配置-->
        <!--<property name="configuration" ref="configuration"></property>-->
        <!-- 注入全域性配置策略-->
        <property name="globalConfig" ref="globalConfiguration"></property>

        <!-- 2、第二種方式,在 applicationContext.xml 檔案中引入分頁外掛-->
        <property name="plugins">
            <list>
                <!-- 分頁查詢外掛 -->
                <bean id="paginationInterceptor"
                      class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
                    <property name="dialectType" value="mysql"/>
                </bean>

                <!-- 執行分析外掛 只建議在開發環境中使用,不建議在生產環境使用 -->
                <bean class="com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor">
                    <property name="sqlParserList">
                            <!-- 禁止全表刪除-->
                        <bean class="com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser"></bean>
                    </property>
                </bean>

                <!-- 樂觀鎖外掛,做這個測試的時候,需要給實體類接一個version欄位,相應的也需要在資料庫中新增該欄位 -->
                <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"></bean>
            </list>
        </property>

    </bean>

    <!--這個等於Mybatis的全域性配置檔案,如果在MybatisSqlSessionFactoryBean裡面已經配置了configLocation屬性(外部載入Mybatis全域性配置檔案),就不能再配置configuration屬性-->
    <bean id="configuration" class="com.baomidou.mybatisplus.core.MybatisConfiguration">
        <!--開啟駝峰命名-->
        <property name="mapUnderscoreToCamelCase" value="true"/>
        <!--日誌列印SQL語句-->
        <property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"></property>
    </bean>

    <!-- 定義mybatis-plus全域性策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
        <!-- 全域性主鍵策略-->
        <property name="dbConfig" ref="dbConfig"></property>
    </bean>
    <!-- 這裡-->
    <bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
        <!-- 全域性表主鍵生成策略 -->
        <property name="idType" value="AUTO"></property>
        <!-- 全域性的表字首策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>
    </bean>

    <!--
    配置 mybatis 掃描 mapper 介面的路徑
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage"
                  value="com.mp.mapper"></property>
    </bean>
</beans>
複製程式碼

mp06的程式碼結構如下所示:

mp06-03.png

至此,基於 mybatis-plus 的外掛拓展演示就完成了,下面我們就可以進入到下一節自定義全域性操作和全域性sql注入的學習了。

原始碼

相關示例完整程式碼:mybatis-plus-in-action