1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        PageHelper導(dǎo)致自定義Mybatis攔截器不生效

        共 4758字,需瀏覽 10分鐘

         ·

        2021-04-19 15:00


        來源:www.jianshu.com/p/8dc9f8a4cce9

        背景:

        最近由于公司要做統(tǒng)一的數(shù)據(jù)變更記錄,以前是基于Aop來做的,這樣效率很低,而且在做批量處理(insert,update,delete)操作時基本不可用。所以我打算使用CDC(如Canal,Maxwell等工具)來監(jiān)聽mysql的binlog來做。

        但是不是所有的表都會有user_id字段,所以我們須要在sql上做一些處理,因為公司現(xiàn)在統(tǒng)一用的是mybatis,那么現(xiàn)在我覺得比較好的方式就是在mybatis上進行攔截改造sql.將userId從應(yīng)用層獲取到并寫入到須要執(zhí)行的sql上(只對insert,update,delete記錄)。

        如:有如下sql:

        update table set a= 1 where name =3

        改造的結(jié)果就是:

        /** userId:1,traceId:123456**/ 
        update table set a= 1 where name =3

        這樣我們就可以記錄一次操作改了哪些數(shù)據(jù),改數(shù)據(jù)的人是哪個。

        開始干:

        這里面有幾個技術(shù)點,且都不怎么復(fù)雜,今天我們只聊mybatis攔截器。其實寫一個攔截器還是很簡單的,網(wǎng)上有很多的代碼。代碼寫完后,突然發(fā)現(xiàn)有些項目的自定義mybatis攔截器沒有生效。

        于是就開始google研究了一下,發(fā)現(xiàn)是因為我們這些不生效的項目使用了PageHelper.于是找了一些大神的解決方案,和攔截器的順序有關(guān)。先說一下結(jié)論:

        MyBatis的攔截器采用責(zé)任鏈設(shè)計模式,多個攔截器之間的責(zé)任鏈?zhǔn)峭ㄟ^動態(tài)代理組織的。我們一般都會在攔截器中的intercept方法中往往會有invocation.proceed()語句,其作用是將攔截器責(zé)任鏈向后傳遞,本質(zhì)上便是動態(tài)代理的invoke。

        PageHelper在intercept方法中執(zhí)行完后沒有執(zhí)行invocation.proceed(),意味著這玩意兒沒有繼續(xù)傳遞責(zé)任鏈(可能他有自己的想法)。所以他就沒有進入我們自己的攔截器。

        注意,敲黑板:

        A.不是所有的攔截器都必須要指定先后順序。

        攔截器的調(diào)用順序分為兩大種,第一種是攔截的不同對象,例如攔截 Executor 和 攔截 StatementHandler 就屬于不同的攔截對象, 這兩類的攔截器在整體執(zhí)行的邏輯上是不同的,在 Executor 中的 query 方法執(zhí)行過程中會調(diào)用StatementHandler。

        所以StatementHandler 屬于 Executor 執(zhí)行過程中的一個子過程。所以這兩種不同類別的插件在配置時,一定是先執(zhí)行 Executor 的攔截器,然后才會輪到 StatementHandler。所以這種情況下配置攔截器的順序就不重要了,在 MyBatis 邏輯上就已經(jīng)控制了先后順序。

        所以如果你一個是Executor 類型的攔截器,一個是StatementHandler類型的攔截器,你可以不用管他順序,也就是說你只須要定義好類型都Executor的攔截器順序。

        B.類型都為Executor的攔截器順序問題。

        如果你的攔截器定義的順序是這樣的(你可以通過獲取sqlSessionFactory.getConfiguration()去查看里面的InterceptorChain然后看到各個interceptor的順序):

        <plugins>
        <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor1"/>
        <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor2"/>
        <plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor3"/>
        </plugins>

        他執(zhí)行的順序不是先執(zhí)行1,2,3,而執(zhí)行的順序是3,2,1。

        Interceptor3:{
            Interceptor2: {
                Interceptor1: {
                    target: Executor
                }
            }
        }

        從這個結(jié)構(gòu)應(yīng)該就很容易能看出來,將來執(zhí)行的時候肯定是按照 3>2>1>Executor>1>2>3 的順序去執(zhí)行的??赡苡行┤瞬恢罏槭裁?>2>1>Executor之后會有1>2>3,這是因為使用代理時,調(diào)用完代理方法后,還能繼續(xù)進行其他處理。處理結(jié)束后,將代理方法的返回值繼續(xù)往外返回即可。

        C.解決方案

        因為PageHelper是Excetor類型的攔截器,所以按照前面兩條的理論,我們?nèi)绻胍赑ageHelper攔截器前面執(zhí)行,就必須要將我們自己的攔截器添加到他的攔截器后面。

        那該怎么做呢?

        我們可以通過這種方式來做:

        我們?nèi)タ碢ageHelperAutoConfiguration的代碼是不是發(fā)現(xiàn),該類上面有一個@AutoConfigureAfter(MybatisAutoConfiguration.class)注解,這表明他是在MybatisAutoConfiguration加載完成后,才執(zhí)行自己的加載。那么我們是不是可以也可以構(gòu)建一個類似的代碼呢,雖然我們不是一個starter,但是我們可以通過這種操作來實現(xiàn)我們的須求。

        1.在src/main/resources/META-INF目錄下面,創(chuàng)建一個spring.factories的文件

        2.spring.factories里的內(nèi)容是:org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.llyt.exculd.TestLogAutoConfiguration這個com.llyt.exculd.TestLogAutoConfiguration,就是你自己的配置類的全路徑。該類的代碼在后面。

        3.TestLogAutoConfiguration代碼:

        @Configuration
        @AutoConfigureAfter(PageHelperAutoConfiguration.class)
        public class TestLogAutoConfiguration 
        {
            @Autowired
            private List<SqlSessionFactory> sqlSessionFactoryList;

            @PostConstruct
            public void addMyInterceptor() {
                ExampleOnePlugin e = new ExampleOnePlugin();
                for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
                    sqlSessionFactory.getConfiguration().addInterceptor(e);
                }
            }
        }

        至此,這種方法就OK了。但是你可能會執(zhí)行不成功,該類的addMyInterceptor方法總是先于PageHelperAutoConfiguration的addPageInterceptor()方法執(zhí)行,這就意味著你的攔截器總是添加到在pageHelper攔截前面的,那么他總是在PageHelper攔截器后面執(zhí)行。

        如果出現(xiàn)這種情況,說明你可能在spring boot主類上配置了

        @ComponentScan("****"),且該類會被這個掃描到,這個就是導(dǎo)致的原因所在。

        這里面有一個知識點就是,不是配置了@AutoConfigureAfter(A.class)就一定表示該類一定在A類后面執(zhí)行。

        如果配置類在 spring.factories 中配置了且而如果你的類被自己 Spring Boot 啟動類掃描到了,那么該類會被會優(yōu)先掃描到,配置類對順序有要求時就會出錯。那么該怎么解決呢?

        解決的方法有兩個:

        a.使用騷操作。

        如果你將自己的配置類放到特別的包下,不使用 Spring Boot 啟動類掃描。完全通過 spring.factories 讀取配置就可以實現(xiàn)這個目的。

        比如,你@ComponentScan掃描的包是com.bb.cc,那么你就將該配置類放在com.bb.dd包下面。

        b.如果你覺得上面這種不習(xí)慣,可以用使用excludeFilters。

        @ComponentScan(basePackages = {"com.llyt"},  excludeFilters = @ComponentScan.Filter(
             type = FilterType.REGEX,
             pattern = "com.llyt.exculd.*"))

        將你的配置類放在com.llyt.exculd包下面就行了。

        至此,mybatis攔截器的不生效的問題,搞完了。

        最近給大家找了  JVM學(xué)習(xí)視頻


        資源,怎么領(lǐng)?。?/span>


        掃二維碼為,加我微信,回復(fù):JVM

         注意,不要亂回復(fù) 

        沒錯,不是機器人
        記得一定要等待,等待才有好東西
        瀏覽 52
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            插吧插吧综合网 | 日韩成人电影中文字幕 | 室友让我喂他吃我的j精子 | 日韩一级片无码 | 水蜜桃成人网站 | 涩涩视频在线观看免费 | 欧美成人性爱视频在线播放 | 抽插.com | 色婷婷一级片 | 国产91网红主播在线观看 |