常見遞歸樹
一般在我們做背景管理的時候都需要加載一個樹,當然也有更好的方法,一般後端都是直接請求一個接口然後傳回一個樹,樹一般都是遞歸調用的,根據父級一層層的往下查詢,然後大部人都是這麼做的。

不知你們都是怎麼做的反正我看到的背景管理的大部分都是怎麼搞的,前面查詢出父級的菜單,然後将父級所需的一些資訊傳到構造的遞歸函數中,然後接着查詢下一級,這樣一級級的往下查,最終構造成一個樹。
前端根據這個樹解析填充,但是一旦這個樹的資料很大的時候,查詢就非常的慢,查詢慢我們就得優化吧,但是sql語句已經優化的差不多了,就是要把遞歸查詢資料庫優化掉。
優化第一種思路
首先我們想到是一次性查詢所有的資料将資料放入到緩存中,那就寫一個List集合将所有的資料都放到集合中,但是這個資料是實時變動的,你放到List的集合中他是不變的還行,但是一變動還是查詢的原來的資料就做不到實時的改變了。而且集合放的資料過多還會造成記憶體溢出的問題。
優化第二種思路
将這個集合放到redis集合中,每一次查詢都時候都重新設定下緩存,然後再查詢,雖說這樣第一次查詢會很慢,但是後面的查詢都會很快。但是問題又來了,這個背景管理是很多使用者的,每個使用者的菜單樹都是不一樣,這就很操蛋了,你還得對不同的使用者都存一個樹,每次改變都得設定下redis緩存,這并發一多還不得直接卡死啊。
優化第三種思路
經過前幾種的思路後我們想着查詢父級的時候根據父級的id查詢每個使用者的菜單樹放入到redis中,然後在每個使用者登入的時候重新整理下自己的緩存,這個即解決了每個使用者不同菜單樹緩存的問題又解決了第一次查詢很慢的問題。
優化第四種思路
雖然第三種方法看上去不錯,但是這個又做不到實時查詢菜單樹的問題了,想想能不能每次有使用者操作的時候都更新下對應的緩存呢?于是就寫一個AOP切面對每個操作了菜單的方法進行redis緩存的更新,也是可以擷取到不同的使用者對其更改,這樣就完美的解決了。
最後
邏輯該怎麼寫呢?
這是大緻的操作步驟,按這個篩選是沒有問題的。至于AOP就很簡單了這就不貼了,就是寫個AOP注解對需要的方法進行操作即可。
最後
這裡還有個問題對于redis的設定值一般都喜歡這麼寫
public <T> void put(String key, T obj, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(obj),timeout,unit);
}
複制
這個寫如果轉換的obj裡面的對象有值是空的他會直接的去掉,避免這個問題可以這麼寫
public <T> void put(String key, T obj, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue),timeout,unit);
}
複制