歡迎您光臨本站 註冊首頁

AutoLoadCache 7.0.4 發布,完善 Magic 模式

←手機掃碼閱讀     admin @ 2019-07-16 , reply:0

7.0.4 版本修改日誌:

1. 修復了Magic模式下數據不正確問題;

2. 支持無參函數下使用Magic模式;

3. 對Magic模式下的緩存刪除功能進行重構,不僅支持基於參數進行批量刪除緩存,也支持通過返回進行批量刪除緩存;

下面是對Magic模式的詳細說明:

為了降低緩存數據與數據源數據不一致,也是為了更加方便更新、刪除緩存,通常做法是,數據以主鍵為key進行緩存,然後根據id獲取數據,如下面兩段代碼所示:


public interface UserMapper {
    
    /**
     * 根據用戶id獲取用戶信息
     * 
     * @param id
     * @return
     */
    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60", key = "'user-byid-' + #args[0]")
    UserDO getUserById(Long id);

    /**
     * 根據動態組合查詢條件,獲取用戶id列表
     * 
     * @param condition
     * @return
     **/
    List<Long> listIdsByCondition(UserCondition condition);

}

下面是根據一定的查詢用戶信息:


    public List<UserDO> listByCondition(UserCondition condition) {
        List<Long> ids = userMapper.listIdsByCondition(condition);
        List<UserDO> list = null;
        if (null != ids && ids.size() > 0) {
            list = new ArrayList<>(ids.size());
            UserDO userDO = null;
            for (Long id : ids) {
                userDO = userMapper.getUserById(id);
                if (null != userDO) {
                    list.add(userDO);
                }
            }
        }
        return list;
    }

如果上面ids有10條記錄,最差的情況需要訪問10次緩存和10數據源,以及寫10次緩存才能完成以上操作,最好的情況也需要訪問10次緩存才能完成操作。 使用Magic模式,則會將參數分隔,先批量去緩存中查詢,獲取命中的緩存,然後將緩存未命中的,再批量從數據源載入,然後把從數據源載入的數據刷入緩存,最後把緩存命中的與數據源載入的數據一併返回。 下面是使用Magic模式進行優化:


public interface UserMapper {
    
    /**
     * 根據用戶id獲取用戶信息
     * 
     * @param id
     * @return
     */
    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60", key = "'user-byid-' + #args[0]")
    UserDO getUserById(Long id);

    /**
     * 根據動態組合查詢條件,獲取用戶id列表
     * 
     * @param condition
     * @return
     **/
    List<Long> listIdsByCondition(UserCondition condition);
    
    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60",
            key = "'user-byid-' + #args[0]",
            magic = @Magic(key = "'user-byid-' + #retVal.id", iterableArgIndex = 0))
    List<UserDO> listByIds(@Param("ids") List<Long> ids);

    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60",
            // 因為Magic 模式下會對參數進行分隔,所以取參數固定使用 #args[0],
            // 如果參數據是複雜類型,比如List<UserDO>, 那麼取參使用 #args[0].id
            // 為了降低緩存不致問題,些處生的有key值要與getUserById 方法的一樣
            key = "'user-byid-' + #args[0]",
            magic = @Magic(
                    // 因為Magic 模式下會對數組及集合類型的數據進行分隔,所以取返回值固定使用 #retVal,
                    // 此key表達生成的值也必須要與getUserById 方法的一樣
                    key = "'user-byid-' + #retVal.id", iterableArgIndex = 0))
    List<UserDO> listByIds(@Param("ids") List<Long> ids);

    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60",
            // 因為Magic 模式下會對參數進行分隔,所以取參數固定使用 #args[0],
            // 如果參數據是複雜類型,比如List<UserDO>, 那麼取參使用 #args[0].id
            // 為了降低緩存不致問題,些處生的有key值要與getUserById 方法的一樣
            key = "'user-byid-' + #args[0]",
            magic = @Magic(
                    // 因為Magic 模式下會對數組及集合類型的數據進行分隔,所以取返回值固定使用 #retVal,
                    // 此key表達生成的值也必須要與getUserById 方法的一樣
                    key = "'user-byid-' + #retVal.id", iterableArgIndex = 0))
    List<UserDO> listByIds2(@Param("ids") Long... ids);

}

下面是在沒有使用Magic模式下根據一定條件查詢用戶信息,先獲取用戶id列表,然後再遍歷獲取用戶詳細信息:


    public List<UserDO> listByCondition(UserCondition condition) {
        List<Long> ids = userMapper.listIdsByCondition(condition);
        List<UserDO> list = null;
        if (null != ids && !ids.isEmpty()) {
            list = userMapper.listByIds(ids);
        }
        return list;
    }

使用Magic模式后,如果上面ids有10條記錄,最差情況需要訪問1次緩存、1數據源以及1次寫緩存操作;最好的情況只需要訪問1次緩存。但使用Magic模式后,就不允許使用自動載入(autoload設置為true也不會生效)、不支持「拿來主義」、非同步刷新等功能。


    @Cache(expire = 60, expireExpression = "null == #retVal ? 30: 60",
            key = "", magic = @Magic(key = "'user-magic-'+ #retVal.id"))
    public List<UserDO> loadUsers() {
        List<UserDO> list = new ArrayList<>(5);
        for (Long id = 100L; id < 105; id++) {
            list.add(new UserDO(id, "name" + id, "ppp"));
        }
        return list;
    }

有時我們也需要動態精確批量刪除緩存,比如更新一批商品信息后,也要批量刪除緩存,在7.0.1版本之前需要在業務代碼中使用循環操作來實現。 7.0.4版本中增加@CacheDeleteMagicKey 用於開啟Magic模式,並支持對參數或返回值進行分割,然後生成多個Cache key進行批量刪除緩存。如下例子所示:

 


/**
 * 根據用戶ids刪除用戶記錄
 **/
@CacheDelete(magic = { @CacheDeleteMagicKey(value = "'user-byid-' + #args[0]", condition = "#retVal > 0", iterableArgIndex = 0, iterableReturnValue = false) })
int deleteUserByIds(@Param("ids") Long... ids);

// 遍歷ids,刪除所有緩存, iterableReturnValue 必須設置false
@CacheDelete(magic = {
        @CacheDeleteMagicKey(value = "'user-testMagic-' + #args[0] + '-' + #args[1] + '-' + #args[2]", iterableArgIndex = 2, iterableReturnValue = false)
})
public void testDeleteMagicForArg(String name, String password, Long... ids) {

}

// 遍歷返回值,刪除所有緩存,iterableArgIndex必須設置為-1, iterableReturnValue 必須設置為true
@CacheDelete(magic = {
        @CacheDeleteMagicKey(value = "'user-testMagic-' + #args[0] + '-' + #args[1] + '-' + #retVal.id", iterableArgIndex = -1, iterableReturnValue = true)
})
public List<UserDO> testDeleteMagicForRetVal(String name, String password, Long... ids) {
    List<UserDO> list = new ArrayList<>(ids.length);
    for (Long id : ids) {
        list.add(new UserDO(id, name, password));
    }
    return list;
}

使用Magic模式不僅能簡少手動遍歷的代碼,同時也會使用redis的Pipeline批量處理,減少與Redis的交互次數,提升性能。


[admin ]

來源:OsChina
連結:https://www.oschina.net/news/108279/autoloadcache-7-0-4-released
AutoLoadCache 7.0.4 發布,完善 Magic 模式已經有159次圍觀

http://coctec.com/news/all/show-post-209990.html