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

Mybatis-plus多租戶項目實戰(zhàn)進(jìn)階指南

 更新時間:2022年02月09日 15:55:20   作者:碼農(nóng)參上  
多租戶是一種軟件架構(gòu)技術(shù),在多用戶的環(huán)境下共有同一套系統(tǒng),并且要注意數(shù)據(jù)之間的隔離性,下面這篇文章主要給大家介紹了關(guān)于Mybatis-plus多租戶項目實戰(zhàn)進(jìn)階的相關(guān)資料,需要的朋友可以參考下

基于Mybatis-plus實現(xiàn)多租戶架構(gòu)中,介紹了在多租戶項目中如果要開啟一個子線程,那么需要手動進(jìn)行RequestAttributes的子線程共享。如果應(yīng)用場景較少的話可能也不是特復(fù)雜,但是如果場景數(shù)量上來了,還是很容易忘記的,在測試的時候才會發(fā)現(xiàn)疏忽了這一塊。所以想了半天,決定抽取一個公共方法,用來執(zhí)行這些特定的子線程。

既然要復(fù)用這類線程的執(zhí)行方式,線程池是個不錯的選擇。這里省略創(chuàng)建線程池的步驟,選擇直接使用spring內(nèi)已經(jīng)初始化好的線程池ThreadPoolTaskExecutor。下面寫一個工具類,通過線程池啟動子線程,實現(xiàn)下面幾個內(nèi)容:

  • 使用線程池啟動子線程前獲取當(dāng)前的RequestAttributes
  • 在子線程中開啟RequestAttributes的繼承
  • 測試在子線程中能否拿到Request中的租戶信息
@Component
public class AsyncExecutorUtil {
    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public void doMethodWithRequest() {
        ServletRequestAttributes sra = (ServletRequestAttributes) 
              RequestContextHolder.getRequestAttributes();
        threadPoolTaskExecutor.execute(()->{
            RequestContextHolder.setRequestAttributes(sra, true);
            System.out.println(sra.getRequest().getHeader("tenantId"));
        });
    }
}

使用postman進(jìn)行測試,發(fā)現(xiàn)這樣做確實可以實現(xiàn)Request的傳遞,那么下一個問題就來了,我怎么把要執(zhí)行的方法邏輯傳遞給這個線程呢?可能每次要實際執(zhí)行的邏輯都不一樣,所以這里使用函數(shù)式接口來傳遞具體方法的實現(xiàn):

@FunctionalInterface
public interface FunctionInterface {
    void doMethod();
}

修改線程池的執(zhí)行方法,首先保存當(dāng)前RequestAttributes,在啟動的子線程中實現(xiàn)對Request的繼承,最后執(zhí)行函數(shù)式接口的方法:

public void doMethodWithRequest(FunctionInterface  functionInterface) {
    ServletRequestAttributes sra = (ServletRequestAttributes) 
                    RequestContextHolder.getRequestAttributes();
    threadPoolTaskExecutor.execute(()->{
        RequestContextHolder.setRequestAttributes(sra, true);
        System.out.println(sra.getRequest().getHeader("tenantId"));
        functionInterface.doMethod();
    });
}

在web請求中,在函數(shù)式接口中實現(xiàn)實際執(zhí)行的邏輯,這里為了使結(jié)構(gòu)更清楚一些沒有使用lambda表達(dá)式,如果使用lambda表達(dá)式可以使這一段代碼更加簡潔。之后使用上面定義的異步線程工具類在子線程中執(zhí)行數(shù)據(jù)庫的查詢:

@RestController
public class TestController {
    @Autowired
    AsyncExecutorUtil executorUtil;

    @GetMapping("users")
    public void user() {
        executorUtil.doMethodWithRequest(new FunctionInterface() {
            @Override
            public void doMethod() {
                List<User> userList = userService.getUserList();
                log.info(userList.toString());
            }
        });
    }
}

查看執(zhí)行結(jié)果,可以正常執(zhí)行:

[User(id=2, name=trunks, phone=13788886666, address=beijing, tenantId=2)]

到這為止,不知道大家是不是記得之前提過的一個場景,有些時候第三方的系統(tǒng)在調(diào)用我們的接口時可能無法攜帶租戶信息,之后的所有數(shù)據(jù)庫查詢都需要我們使用重新手寫sql,并添加SqlParse的過濾。

舉個例子,我們系統(tǒng)中創(chuàng)建訂單,調(diào)用微信支付,在前端支付成功后微信會回調(diào)我們的接口。這個時候微信是肯定不會攜帶租戶的信息的,按照之前的做法,我們就需要先根據(jù)回調(diào)信息的訂單號先使用過濾過的sql語句查出這筆訂單的信息,拿到訂單中包含的租戶id,在之后所有被過濾掉的手寫sql中手動拼接這個租戶id。

但是有了上面的結(jié)果 ,對我們執(zhí)行這類的請求可以產(chǎn)生一些改變 。之前我們是向子線程傳遞真實的原始Request,但是當(dāng)前的Request請求不滿足我們的需求,沒有包含租戶信息,那么重新構(gòu)建一個符合我們需求的Request,并傳遞給子線程,那么是不是就不用去進(jìn)行sql的過濾和重寫了呢?

按照上面的步驟,先進(jìn)行第一步,手寫一個過濾租戶的sql:

public interface OrderMapper extends BaseMapper<Order> {
    @SqlParser(filter = true)
    @Select("select * from `order` where order_number= #{orderNumber}")
    Order selectWithoutTenant(String orderNumber);
}

根據(jù)這個請求,能夠查詢出訂單的全部信息,這里面就包含了租戶的id:

Order(id=3, orderNumber=6be2e3e10493454781a8c334275f126a, money=100.0, tenantId=3)

接下來重頭戲來了,既然拿到了租戶id,我們就來重新偽造一個Request,讓這個新的Request中攜帶租戶id,并使用這個Request執(zhí)行后續(xù)的邏輯。

@AllArgsConstructor
public class FakeTenantRequest {
    private String tenantId;

    public ServletRequestAttributes getFakeRequest(){
        HttpServletRequest request = new HttpServletRequest() {
            @Override
            public String getHeader(String name) {
                if (name.equals("tenantId")){
                    return tenantId;
                }
                return null;
            }

           //...這里省略了其他需要重寫的方法,不重要,可不用重寫
        };

        ServletRequestAttributes servletRequestAttributes=new ServletRequestAttributes(request);
        return servletRequestAttributes;
    }
}

構(gòu)造一個HttpServletRequest的過程比較復(fù)雜,里面需要重寫的方法非常多,好在我們暫時都用不上所以不用重寫,只重寫對我們比較重要的getHeader方法即可。我們在構(gòu)造方法中傳進(jìn)來租戶id,并把這個租戶id放在Request的請求頭的tenantId字段,最終返回RequestAttributes。

在線程池工具類中添加一個方法,在子線程中使用我們偽造的RequestAttributes:

public void doMethodWithFakeRequest(ServletRequestAttributes fakeRequest, 
        FunctionInterface functionInterface) {
    threadPoolTaskExecutor.execute(() -> {
        RequestContextHolder.setRequestAttributes(fakeRequest, true);
        functionInterface.doMethod();
    });
}

模擬回調(diào)請求,這時候在請求的Header中不需要攜帶任何租戶信息:

@GetMapping("callback")
public void callBack(String orderNumber){
    Order order = orderMapper.selectWithoutTenant(orderNumber);
    log.info(order.toString());
    FakeTenantRequest fakeTenantRequest=new FakeTenantRequest(order.getTenantId().toString());
    executorUtil.doMethodWithFakeRequest(fakeTenantRequest.getFakeRequest(),new FunctionInterface() {
        @Override
        public void doMethod() {
            List<User> userList = userService.getUserList();
            log.info(userList.toString());
        }
    });
}

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

 - ==>  Preparing: select * from `order` where order_number= ? 
 - ==> Parameters: 6be2e3e10493454781a8c334275f126a(String)
 - <==      Total: 1
 - Order(id=3, orderNumber=6be2e3e10493454781a8c334275f126a, money=100.0, tenantId=3)
 - ==>  Preparing: SELECT id, name, phone, address, tenant_id FROM user WHERE (id IS NOT NULL) AND tenant_id = '3' 
 - ==> Parameters: 
 - <==      Total: 1
 - [User(id=1, name=hydra, phone=13699990000, address=qingdao, tenantId=3)]

在子線程中執(zhí)行的sql會經(jīng)過mybatis-plus的租戶過濾器,在sql中添加租戶id條件。這樣,就實現(xiàn)了通過偽造Request的方式極大程度的簡化了改造sql的過程。

總結(jié)

到此這篇關(guān)于Mybatis-plus多租戶項目實戰(zhàn)進(jìn)階指南的文章就介紹到這了,更多相關(guān)Mybatis-plus多租戶內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis中單雙引號引發(fā)的慘案及解決

    Mybatis中單雙引號引發(fā)的慘案及解決

    這篇文章主要介紹了Mybatis中單雙引號引發(fā)的慘案及解決方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java實現(xiàn)的冒泡排序算法示例

    java實現(xiàn)的冒泡排序算法示例

    這篇文章主要介紹了java實現(xiàn)的冒泡排序算法,結(jié)合實例形式分析了冒泡排序算法的具體操作步驟與實現(xiàn)技巧,需要的朋友可以參考下
    2017-01-01
  • java實現(xiàn)導(dǎo)出數(shù)據(jù)為zip壓縮文件

    java實現(xiàn)導(dǎo)出數(shù)據(jù)為zip壓縮文件

    這篇文章主要為大家詳細(xì)介紹了java如何實現(xiàn)導(dǎo)出數(shù)據(jù)為zip壓縮文件,并且解壓后為json文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • Java使用策略模式解決商場促銷商品問題示例

    Java使用策略模式解決商場促銷商品問題示例

    這篇文章主要介紹了Java使用策略模式解決商場促銷商品問題,簡單描述了策略模式的概念、原理,并結(jié)合實例形式分析了Java基于策略模式解決商品促銷問題的相關(guān)操作技巧,需要的朋友可以參考下
    2018-05-05
  • Springmvc加ajax實現(xiàn)上傳文件并頁面局部刷新

    Springmvc加ajax實現(xiàn)上傳文件并頁面局部刷新

    這篇文章主要介紹了Springmvc加ajax實現(xiàn)上傳文件并頁面局部刷新,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Java中CopyOnWriteArrayList的使用解析

    Java中CopyOnWriteArrayList的使用解析

    這篇文章主要介紹了Java中CopyOnWriteArrayList的使用解析,CopyOnWriteArrayList適合使用在讀操作遠(yuǎn)遠(yuǎn)大于寫操作的場景里,比如緩存,它不存在擴(kuò)容的概念,每次寫操作都要復(fù)制一個副本,在副本的基礎(chǔ)上修改后改變Array引用,需要的朋友可以參考下
    2023-12-12
  • Java full gc觸發(fā)情況實例解析

    Java full gc觸發(fā)情況實例解析

    這篇文章主要介紹了Java full gc觸發(fā)情況實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • springboot配置文件中敏感數(shù)據(jù)(賬號密碼)加密方式

    springboot配置文件中敏感數(shù)據(jù)(賬號密碼)加密方式

    這篇文章主要介紹了springboot配置文件中敏感數(shù)據(jù)(賬號密碼)加密方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • java中的static{}塊的實例詳解

    java中的static{}塊的實例詳解

    這篇文章主要介紹了java中的static{}塊的實例詳解的相關(guān)資料,這里提供實例來幫助大家理解該如何使用static塊,需要的朋友可以參考下
    2017-08-08
  • java實現(xiàn)Excel轉(zhuǎn)換為圖片

    java實現(xiàn)Excel轉(zhuǎn)換為圖片

    在實際開發(fā)過程中,經(jīng)常會有這樣的需求,需要將Excel表格或特定區(qū)域轉(zhuǎn)換為圖片,所以小編今天就來為大家介紹一下如何使用Java將Excel轉(zhuǎn)化為圖片吧
    2023-10-10

最新評論

通化县| 新郑市| 雅安市| 运城市| 建平县| 安乡县| 会理县| 泽普县| 偏关县| 瓦房店市| 莎车县| 汉源县| 彰化县| 牙克石市| 凤冈县| 文化| 东至县| 普定县| 天峨县| 绍兴县| 龙口市| 河西区| 灵石县| 土默特左旗| 家居| 山东| 石门县| 溧水县| 罗定市| 淮南市| 汉源县| 辛集市| 安岳县| 东至县| 南充市| 兰坪| 文昌市| 新绛县| 那坡县| 舟曲县| 马山县|