最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL更新的代碼示例

 更新時(shí)間:2023年07月12日 10:47:28   作者:waynaqua  
本文博小編將帶領(lǐng)大家學(xué)習(xí)如何利用 MyBatis 攔截器機(jī)制來優(yōu)雅的實(shí)現(xiàn)這個(gè)需求,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下

本文示例代碼全部在 Spring Boot3.0、Mybatis Plus3.5.3.1 版本下運(yùn)行。

簡(jiǎn)介

MyBatis 是一個(gè)流行的 Java 持久層框架,它提供了靈活的 SQL 映射和執(zhí)行功能。有時(shí)候我們可能需要在運(yùn)行時(shí)動(dòng)態(tài)地修改 SQL 語(yǔ)句,例如添加一些條件、排序、分頁(yè)等。MyBatis 提供了一個(gè)強(qiáng)大的機(jī)制來實(shí)現(xiàn)這個(gè)需求,那就是攔截器(Interceptor)。

攔截器介紹

攔截器是一種基于 AOP(面向切面編程)的技術(shù),它可以在目標(biāo)對(duì)象的方法執(zhí)行前后插入自定義的邏輯。MyBatis 定義了四種類型的攔截器,分別是:

  • Executor:攔截執(zhí)行器的方法,例如 update、query、commit、rollback 等。可以用來實(shí)現(xiàn)緩存、事務(wù)、分頁(yè)等功能。
  • ParameterHandler:攔截參數(shù)處理器的方法,例如 setParameters 等??梢杂脕磙D(zhuǎn)換或加密參數(shù)等功能。
  • ResultSetHandler:攔截結(jié)果集處理器的方法,例如 handleResultSets、handleOutputParameters 等??梢杂脕磙D(zhuǎn)換或過濾結(jié)果集等功能。
  • StatementHandler:攔截語(yǔ)句處理器的方法,例如 prepare、parameterize、batch、update、query 等??梢杂脕硇薷?SQL 語(yǔ)句、添加參數(shù)、記錄日志等功能。

實(shí)現(xiàn)攔截器

  • 定義一個(gè)實(shí)現(xiàn) org.apache.ibatis.plugin.Interceptor 接口的攔截器類,并重寫其中的 intercept、plugin 和 setProperties 方法。
  • 添加 @Intercepts 注解,寫上需要攔截的對(duì)象和方法,以及方法參數(shù),例如 @Intercepts({@Signature(type = StatementHandler.class, method = “prepare”, args = {Connection.class, Integer.class})}),表示在 SQL 執(zhí)行之前進(jìn)行攔截處理。

注冊(cè)攔截器

Spring Boot 項(xiàng)目中集成了 Mybatis Plus 后要讓攔截器生效很簡(jiǎn)單,Mybatis Plus 的自動(dòng)配置類會(huì)讀取項(xiàng)目中所有注冊(cè)到 Spring 容器的攔截器并進(jìn)行自動(dòng)注冊(cè)。如下圖,

所以我們只需要定義一個(gè) DynamicSqlInterceptor 攔截器并加上 @Component 注解就行,代碼如下,

@Component
@Slf4j
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DynamicSqlInterceptor implements Interceptor {
 ...
}

代碼示例

yml 配置

指定 xml 文件中需要替換的占位符標(biāo)識(shí):@dynamicSql 以及待替換日期條件。

# 動(dòng)態(tài)sql配置
dynamicSql:
  placeholder: "@dynamicSql"
  date: "2023-07-10 20:10:30"

Dao 層代碼

在需要進(jìn)行 SQL 占位符替換的方法上加 @DynamicSql 注解。

public interface DynamicSqlMapper {
    @DynamicSql
    Long count();
}

mapper 文件

將日期條件改成占位符 where create_time > @dynamicSql。

<mapper namespace="ltd.newbee.mall.core.dao.DynamicSqlMapper">
    <select id="count" resultType="java.lang.Long">
        select count(1) from member
        where create_time > @dynamicSql
    </select>
</mapper>

攔截器核心代碼

@Component
@Slf4j
@Intercepts({
        @Signature(type = StatementHandler.class, 
                method = "prepare", args = {Connection.class, Integer.class})
})
public class DynamicSqlInterceptor implements Interceptor {
    @Value("${dynamicSql.placeholder}")
    private String placeholder;
    @Value("${dynamicSql.date}")
    private  String dynamicDate;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 1. 獲取 StatementHandler 對(duì)象也就是執(zhí)行語(yǔ)句
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        // 2. MetaObject 是 MyBatis 提供的一個(gè)反射幫助類,可以優(yōu)雅訪問對(duì)象的屬性,這里是對(duì) statementHandler 對(duì)象進(jìn)行反射處理,
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                        new DefaultReflectorFactory());
        // 3. 通過 metaObject 反射獲取 statementHandler 對(duì)象的成員變量 mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // mappedStatement 對(duì)象的 id 方法返回執(zhí)行的 mapper 方法的全路徑名,如ltd.newbee.mall.core.dao.UserMapper.insertUser
        String id = mappedStatement.getId();
        // 4. 通過 id 獲取到 Dao 層類的全限定名稱,然后反射獲取 Class 對(duì)象
        Class<?> classType = Class.forName(id.substring(0, id.lastIndexOf(".")));
        // 5. 獲取包含原始 sql 語(yǔ)句的 BoundSql 對(duì)象
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql();
        log.info("替換前---sql:{}", sql);
        // 攔截方法
        String mSql = null;
        // 6. 遍歷 Dao 層類的方法
        for (Method method : classType.getMethods()) {
            // 7. 判斷方法上是否有 DynamicSql 注解,有的話,就認(rèn)為需要進(jìn)行 sql 替換
            if (method.isAnnotationPresent(DynamicSql.class)) {
                mSql = sql.replaceAll(placeholder, String.format("'%s'", dynamicDate));
                break;
            }
        }
        if (StringUtils.isNotBlank(mSql)) {
            log.info("替換后---mSql:{}", mSql);
            // 8. 對(duì) BoundSql 對(duì)象通過反射修改 SQL 語(yǔ)句。
            Field field = boundSql.getClass().getDeclaredField("sql");
            field.setAccessible(true);
            field.set(boundSql, mSql);
        }
        // 9. 執(zhí)行修改后的 SQL 語(yǔ)句。
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        // 使用 Plugin.wrap 方法生成代理對(duì)象
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties) {
        // 獲取配置文件中的屬性值
    }
}

現(xiàn)在我們對(duì)攔截器核心代碼邏輯進(jìn)行講解:

  • 通過 invocation 參數(shù)獲取 statementHandler 對(duì)象,也就是包含拼接后 SQL 語(yǔ)句的對(duì)象。
  • 獲取 metaObject 對(duì)象, MetaObject 是 MyBatis 提供的一個(gè)反射幫助類,可以優(yōu)雅訪問對(duì)象的屬性,這里是訪問 statementHandler 對(duì)象進(jìn)行反射處理。
  • 通過 metaObject 反射獲取 statementHandler 對(duì)象的成員變量 mappedStatement。
  • 通過 mappedStatement 對(duì)象的 id 方法獲取到 Dao 層類的全限定名稱,然后反射獲取 Dao 層類的 Class 對(duì)象。
  • 獲取包含原始 SQL 語(yǔ)句的 BoundSql 對(duì)象。
  • 遍歷 Dao 層類的方法。
  • 判斷方法上是否有 DynamicSql 注解,有的話就進(jìn)行時(shí)間條件替換。
  • 對(duì) BoundSql 對(duì)象通過反射修改 SQL 語(yǔ)句。
  • 執(zhí)行修改后的 SQL 語(yǔ)句。

代碼測(cè)試

// 測(cè)試類
@SpringBootTest
@RunWith(SpringRunner.class)
public class DynamicTest {
    @Autowired
    private DynamicSqlMapper dynamicSqlMapper;
    @Test
    public void test() {
        Long count = dynamicSqlMapper.count();
        Assert.notNull(count, "count不能為null");
    }
}

執(zhí)行結(jié)果:

2023-07-11 22:13:33.375 [main] INFO  l.n.m.config.DynamicSqlInterceptor - [intercept,52] - 替換前---sql:select count(1) from member
        where create_time > @dynamicSql
2023-07-11 22:13:33.376 [main] INFO  l.n.m.config.DynamicSqlInterceptor - [intercept,62] - 替換后---mSql:select count(1) from member
        where create_time > '2023-07-10 20:10:30'

攔截器應(yīng)用場(chǎng)景

  • SQL 語(yǔ)句執(zhí)行監(jiān)控:可以攔截執(zhí)行的 SQL 方法,打印執(zhí)行的 SQL 語(yǔ)句、參數(shù)等信息,并且還能夠記錄執(zhí)行的總耗時(shí),可供后期的 SQL 分析時(shí)使用。
  • SQL 分頁(yè)查詢:MyBatis 中使用的 RowBounds 使用的內(nèi)存分頁(yè),在分頁(yè)前會(huì)查詢所有符合條件的數(shù)據(jù),在數(shù)據(jù)量大的情況下性能較差。通過攔截器,可以在查詢前修改 SQL 語(yǔ)句,提前加上需要的分頁(yè)參數(shù)。
  • 公共字段的賦值:在數(shù)據(jù)庫(kù)中通常會(huì)有 createTime , updateTime 等公共字段,這類字段可以通過攔截統(tǒng)一對(duì)參數(shù)進(jìn)行的賦值,從而省去手工通過 set 方法賦值的繁瑣過程。
  • 數(shù)據(jù)權(quán)限過濾:在很多系統(tǒng)中,不同的用戶可能擁有不同的數(shù)據(jù)訪問權(quán)限,例如在多租戶的系統(tǒng)中,要做到租戶間的數(shù)據(jù)隔離,每個(gè)租戶只能訪問到自己的數(shù)據(jù),通過攔截器改寫 SQL 語(yǔ)句及參數(shù),能夠?qū)崿F(xiàn)對(duì)數(shù)據(jù)的自動(dòng)過濾。
  • SQL 語(yǔ)句替換:對(duì) SQL 中條件或者特殊字符進(jìn)行邏輯替換。(也是本文的應(yīng)用場(chǎng)景)

總結(jié)

到此本文講解的 MyBatis 實(shí)現(xiàn)動(dòng)態(tài) SQL 內(nèi)容就講解完畢了,希望大家喜歡。

以上就是MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL更新的代碼示例的詳細(xì)內(nèi)容,更多關(guān)于MyBatis動(dòng)態(tài)SQL更新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中Collections.sort的使用

    Java中Collections.sort的使用

    本文主要介紹了Java中Collections.sort的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • java查看當(dāng)前jvm項(xiàng)目使用的垃圾回收器的實(shí)現(xiàn)方式

    java查看當(dāng)前jvm項(xiàng)目使用的垃圾回收器的實(shí)現(xiàn)方式

    文章介紹了三種方法來查看Java應(yīng)用程序使用的垃圾回收器:使用jconsole工具、運(yùn)行代碼打印參數(shù)以及使用命令行查看jps和vm參數(shù),默認(rèn)情況下,Java 8使用ParallelGC垃圾回收器,其中老年代使用ParallelOldGC
    2026-03-03
  • 如何基于Java實(shí)現(xiàn)對(duì)象List排序

    如何基于Java實(shí)現(xiàn)對(duì)象List排序

    這篇文章主要介紹了如何基于Java實(shí)現(xiàn)對(duì)象List排序,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java的四種引用方式

    Java的四種引用方式

    這篇文章主要介紹了Java的四種引用方式,Java的引用方式主要包括強(qiáng)引用、軟引用、弱引用、虛引用;下面文章便來詳細(xì)介紹這四種引用方式,需要的朋友可以參考一下
    2021-10-10
  • SpringMVC框架使用 Apache POI實(shí)現(xiàn)導(dǎo)出Excel

    SpringMVC框架使用 Apache POI實(shí)現(xiàn)導(dǎo)出Excel

    Excel 作為最常用的數(shù)據(jù)處理工具之一,經(jīng)常被用來存儲(chǔ)和展示數(shù)據(jù),本文將介紹如何在 SpringMVC 框架中使用 Apache POI 庫(kù)來實(shí)現(xiàn) Excel 文件的導(dǎo)出功能,有需要的可以參考一下
    2025-04-04
  • IDEA配置Maven教程的超詳細(xì)講解版

    IDEA配置Maven教程的超詳細(xì)講解版

    IntelliJ IDEA是當(dāng)前最流行的Java IDE(集成開發(fā)環(huán)境)之一,也是業(yè)界公認(rèn)最好用的Java開發(fā)工具之一,這篇文章主要給大家介紹了關(guān)于IDEA配置Maven教程的超詳細(xì)講解版,需要的朋友可以參考下
    2023-11-11
  • MyBatis-Plus 動(dòng)態(tài)表名SQL解析器的實(shí)現(xiàn)

    MyBatis-Plus 動(dòng)態(tài)表名SQL解析器的實(shí)現(xiàn)

    這篇文章主要介紹了MyBatis-Plus 動(dòng)態(tài)表名SQL解析器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Spring循環(huán)依賴代碼演示及解決方案

    Spring循環(huán)依賴代碼演示及解決方案

    這篇文章主要介紹了Spring循環(huán)依賴實(shí)現(xiàn)過程,Spring的解決循環(huán)依賴是有前置條件的,要解決循環(huán)依賴我們首先要了解Spring Bean對(duì)象的創(chuàng)建過程和依賴注入的方式
    2023-04-04
  • 深入Java萬物之母Object類詳情

    深入Java萬物之母Object類詳情

    這篇文章主要介紹了Java萬物之母Object類詳情,Object類,它是所有類的默認(rèn)父類 ,子類不用使用extends關(guān)鍵字繼承它,不管是JDK中的類,還是自定義的類
    2022-06-06
  • 關(guān)于fastjson的@JSONField注解的一些問題(詳解)

    關(guān)于fastjson的@JSONField注解的一些問題(詳解)

    下面小編就為大家?guī)硪黄P(guān)于fastjson的@JSONField注解的一些問題(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02

最新評(píng)論

华容县| 澳门| 湛江市| 布拖县| 永登县| 双柏县| 林芝县| 加查县| 礼泉县| 柘城县| 海丰县| 琼结县| 龙江县| 淳安县| 临海市| 元谋县| 乌鲁木齐市| 五大连池市| 合作市| 五寨县| 陵川县| 周至县| 阿拉善盟| 六安市| 中山市| 景德镇市| 重庆市| 临洮县| 石首市| 博野县| 绵阳市| 泗洪县| 达日县| 彭泽县| 视频| 晋州市| 确山县| 青海省| 汶上县| 库尔勒市| 天等县|