最近完成了群組模塊的簡單的CRUD的編寫,在編寫過程中使用了Mybatis Plus爽蝴,好好地偷了一把懶沐批。不得不說MP是真的香,不僅節(jié)省了很多寫mapper數(shù)據(jù)庫配置蝎亚、mapper接口的時間九孩,甚至還提供了很多鍵的自增的策略,鍵的自填充策略等发框。最有料的還是代碼的逆向生成了躺彬,雖然對達夢數(shù)據(jù)庫的小寫模式不友好,需要自己寫入實體類的字段梅惯,但是其他方面都還好宪拥。
哦,當然了铣减,如果想的話她君,可以直接在controller中調(diào)用BaseService中的方法進行數(shù)據(jù)庫的操作,但是為了讓控制層看著簡潔一點葫哗,這里還是把業(yè)務(wù)邏輯放在了Service的實現(xiàn)中缔刹。By the way,如果想的話劣针,還可以直接開啟Active Record模式校镐,直接通過實例對象進行數(shù)據(jù)庫的操作。
MP當然還提供了邏輯刪除(deleted)捺典,樂觀鎖(version)鸟廓,多租戶(tenant_id),這些的實現(xiàn)類似辣苏,都是在sql中多加入了一個條件肝箱,雖然原理簡單,但將這些邏輯交給MP稀蟋,實屬方便煌张。
當然上述的種種,說破天就是一個CRUD退客,我們的真的業(yè)務(wù)邏輯和架構(gòu)需求如下:
1. 緩存的構(gòu)建
如果只是針對單套CRUD的操作而言骏融,或者直接說链嘀,針對單個Mapper進行緩存,那么直接采用Mybatis的二級緩存档玻,何樂而不為呢怀泊?二級緩存可以針對select方法進行緩存,針對update误趴、delete方法進行緩存刪除霹琼,但是目前的項目中,顯然不是這樣的場景凉当。
幾個Mapper之間存在一定的交互枣申,即存在多表查詢的情況,那么又有下面兩種情況:
- 兩個Mapper在同一個服務(wù)器上看杭,那么可以通過cache-ref將緩存空間指向另一個Mapper忠藤,可以實現(xiàn)多表的二級緩存,但是這樣的話楼雹,只要有一個表更新或者刪除都會更新緩存模孩,在無形中增加了開銷,且使用不當贮缅,會存在臟數(shù)據(jù)
- 兩個Mapper不在一個服務(wù)器上......??榨咐,不用多說了吧。
所以建議携悯,還是一般情況下祭芦,僅在單表情況下使用二級緩存(或者遵守二級緩存的注意事項)
所以還是自己實現(xiàn)緩存邏輯比較合適筷笨。
那么這里就涉及到了另一點:如何感知其他微服務(wù)對數(shù)據(jù)源的操作憔鬼,進而更新緩存呢?
一個簡單的應(yīng)用場景:
Ⅰ服務(wù)用到了A(x)胃夏,B(x,y)兩張表轴或,其中均有x字段,并通過該字段進行關(guān)聯(lián)仰禀,Ⅱ服務(wù)中用到了C(y)表照雁,其中存在y字段,當Ⅰ服務(wù)通過相關(guān)的SQL語句答恶,獲取了x,y字段饺蚊,并以一種數(shù)據(jù)結(jié)構(gòu)存入了redis,那么當Ⅱ服務(wù)通過C表修改了y字段悬嗓,此時污呼,用戶在該階段去讀取redis種的緩存時,緩存中的y字段包竹,即為臟數(shù)據(jù)燕酷。
那么問題就來了籍凝,如何做到redis中的字段和數(shù)據(jù)庫中的字段同步?或者苗缩,換一個角度饵蒂,如何做到,在其他服務(wù)操作了與redis中相關(guān)字段對應(yīng)的數(shù)據(jù)庫字段后酱讶,redis如何同步更新退盯?
根據(jù)初步調(diào)研,阿里推出的一個開源的數(shù)據(jù)同步中間件canal泻肯,可能可以解決這個問題得问,但是!软免! 項目中使用的是DM數(shù)據(jù)庫宫纬,中間件并不支持。??
2. 數(shù)據(jù)更新的問題
上面的問題膏萧,是針對緩存的漓骚,直白點兒,就是針對redis和數(shù)據(jù)庫的同步問題的榛泛,而下面要講的問題蝌蹂,是針對兩個數(shù)據(jù)庫之間的。
說到這里曹锨,相信很多盆友孤个,都想到了分布式事務(wù)的處理方案,如阿里三件套中的seata沛简,但是以目前個人的了解齐鲤,似乎,并不能解決類似的問題
我們在采用微服務(wù)架構(gòu)之后椒楣,微服務(wù)的數(shù)據(jù)庫之間存在上述的一種關(guān)聯(lián)给郊,當我們在單庫或者說單schema中可以交由數(shù)據(jù)庫,通過簡單而暴力的級聯(lián)刪除處理捧灰,但是在分布式架構(gòu)下淆九,我們表不會在一個庫中,甚至不會在一臺服務(wù)器上毛俏,這時炭庙,就需要思考如何在這種情況下進行數(shù)據(jù)的"級聯(lián)"更新刪除。
目前想到的幾種不成熟的方案:
- 通過消息隊列煌寇,讓"外鍵"服務(wù)(這里本人指的就是內(nèi)含外鍵的服務(wù)焕蹄,且外鍵是待刪除的條目主鍵),訂閱|監(jiān)聽“主鍵”服務(wù)唧席,當“主鍵”服務(wù)調(diào)用刪除的時候擦盾,通知“外鍵”服務(wù)嘲驾,刪除其中相關(guān)的條目。
- “外鍵”微服務(wù)暴露根據(jù)“外鍵”刪除條目的接口迹卢,在“主鍵”服務(wù)的刪除操作中辽故,調(diào)用“外鍵”服務(wù)的相關(guān)接口,進行相關(guān)數(shù)據(jù)的刪除【耦合度較高】
- 與第二種類似腐碱,只不過誊垢,將這種統(tǒng)一的刪除提取為一個服務(wù),該服務(wù)中症见,托管了根據(jù)特定鍵喂走,刪除相關(guān)表中字段的服務(wù)∧弊鳎【耦合度較低】
3. 位置共享服務(wù)
又談到了老問題上芋肠,如何在位置共享的時候,如何將最新的位置推送給相關(guān)的群組中呢遵蚜?
這里用到實時位置帖池,同時還要進行保存,還要供前端進行顯示(就不讓前端去數(shù)據(jù)庫里找了)吭净,甚至還可能對接其他的服務(wù)睡汹。
目前的初步想法:
提取一個位置獲取的微服務(wù),用于獲取節(jié)點寂殉,或者說用戶的實時位置囚巴,獲取之后有三種處理情況:
- 存入數(shù)據(jù)庫
- 存入redis
- 發(fā)送給前端顯示
那么回到最初的問題,群組如何響應(yīng)式地獲取用戶的位置友扰?即在用戶位置更新時彤叉,才進行相應(yīng)用戶的更新,如果用戶關(guān)閉共享焕檬,及時在群組中剔除該用戶姆坚?
當用戶對某個群組開啟共享時,用戶開始訂閱當前群組中的所有在線用戶的位置实愚,這里,訂閱的數(shù)據(jù)源就是來自位置獲取微服務(wù)兔辅,所以腊敲,這個服務(wù),要能夠得知维苔,哪些用戶在哪些群組碰辅?這些用戶的實時位置?并維護好實時的用戶群組表介时!當?shù)玫饺航M服務(wù)的訂閱請求時没宾,要能夠?qū)⒋粲嗛喨航M中的用戶位置信息進行返回凌彬。