1. 程式人生 > >企業專案開發--本地快取guava cache(1)

企業專案開發--本地快取guava cache(1)

此文已由作者趙計剛授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。


1、在實際專案開發中,會使用到很多快取技術,而且資料庫的設計一般也會依賴於有快取的情況下設計。

  • 常用的快取分兩種:本地快取和分散式快取。

  • 常用的本地快取是guava cache,本章主要介紹guava cache在專案中的使用。

關於常用快取以及每種快取常用場景的介紹,之後可以去檢視我記錄的"Java快取相關"系列部落格。連結如下:

第一章 常用的快取技術

 

2、實際使用

本專案的程式碼基於第六章的程式碼進行構建,這裡只列出修改過的程式碼:



2.1、ssmm0-data

pom.xml:

        <!-- guava cache -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>14.0.1</version>
        </dependency>

在pom.xml中引入了guava cache14.0.1的依賴包。

AdminMapper:

package com.xxx.mapper.userManagement;

import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import com.xxx.model.userManagement.Admin;

/**
 * 管理員Mapper
 */
public interface AdminMapper {
    
    /**************註解**************/
    @Insert("INSERT INTO userinfo(username, password) VALUES(#{username},#{password})")
    public int insertAdmin(Admin admin);

    @Select("SELECT * FROM userinfo WHERE username = #{username} AND password = #{password}")
    @Results(value = { 
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password") })
    public Admin selectAdmin(@Param("username") String username,
                             @Param("password") String password);
    
    /***************xml**************/
    /**
     * 條件不定式查詢
     * 我們這裡使用@Param指定引數,這樣的話,在AdminMapper.xml中就不用再使用parameterType屬性了;否則得寫parameterType屬性
     */
    public List<Admin> getAdminByConditions(@Param("username")String username,
                                            @Param("password")String password, 
                                            @Param("start")int start, 
                                            @Param("limit")int limit);
    
    /**
     * 返回主鍵
     */
    public int insertAdminWithBackId(Admin admin);
    
    /****************guava cache*****************/
    @Select("SELECT * FROM userinfo WHERE username = #{username}")
    @Results(value = { 
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password") })
    public List<Admin> getUserByName(@Param("username") String username);
}

將使用到的兩個方法:

  • public List<Admin> getUserByName(String username)

  • public List<Admin> getAdminByConditions(String username, String password, int start, int limit)

AdminDao:

package com.xxx.dao.userManagement;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.xxx.mapper.userManagement.AdminMapper;
import com.xxx.model.userManagement.Admin;

/**
 * 管理員DAO
 */
@Repository
public class AdminDao {
    @Autowired
    private AdminMapper adminMapper;
    /***************註解*****************/
    public boolean register(Admin admin){
        return adminMapper.insertAdmin(admin)==1?true:false;
    }
    
    public Admin login(String username ,String password){
        return adminMapper.selectAdmin(username, password);
    }
    /****************xml******************/
    public List<Admin> findAdmin(String username, String password, int start, int limit){
        return adminMapper.getAdminByConditions(username, password, start, limit);
    }
    
    public int insertAdminWithBackId(Admin admin){
        return adminMapper.insertAdminWithBackId(admin);
    }
    /******************guava cache********************/
    public List<Admin> getUserByName(String username){
        return adminMapper.getUserByName(username);
    }
}

將使用到的兩個方法:

  • public List<Admin> getUserByName(String username)

  • public List<Admin> findAdmin(String username, String password, int start, int limit)

AdminService:

package com.xxx.service.userManagement;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.xxx.dao.userManagement.AdminDao;
import com.xxx.model.userManagement.Admin;
import com.xxx.vo.userManagement.AdminCacheKey;

/**
 * 管理員service
 */
@Service
public class AdminService {
    @Autowired
    private AdminDao adminDao;

    public boolean register(Admin admin) {
        return adminDao.register(admin);
    }

    public Admin login(String username, String password) {
        return adminDao.login(username, password);
    }

    /*********** 以下方法是為了測試mybatis中使用xml **********/
    public List<Admin> findAdmin(String username, 
                                 String password, 
                                 int start,
                                 int limit) {
        return adminDao.findAdmin(username, password, start, limit);
    }

    public Admin insertAdminWithBackId(Admin admin) {
        int record = adminDao.insertAdminWithBackId(admin);
        if (record == 1) {
            return admin;// 這時的admin已經被賦予主鍵了
        }
        return null;
    }

    /************************ guava cache *************************/
    /************單條件的查詢,key為String***********/
    public List<Admin> findByUsername(String username) {
        List<Admin> adminList = null;
        try {
            adminList = adminListCache.get(username);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return adminList;
    }

    LoadingCache<String, List<Admin>> adminListCache = CacheBuilder.newBuilder()
            .expireAfterWrite(20, TimeUnit.MINUTES)// 快取20分鐘
            .maximumSize(1000)// 最多快取1000個物件
            .build(new CacheLoader<String, List<Admin>>() {
                public List<Admin> load(String username) throws Exception {
                    return adminDao.getUserByName(username);
                }
            });

    /************多條件的查詢,key為Object(封裝了多個條件的VO類)***********/
    public List<Admin> findAdminList(String username, 
                                     String password,
                                     int start, 
                                     int limit) {
        /*
         * 注意:
         * 如果以一個新建的物件做為key的話,因為每次都是新建一個物件,所以這樣的話,實際上每次訪問key都是不同的,即每次訪問都是重新進行快取;
         * 但是實際上,我們想要根據物件的屬性來判斷物件是否相等,只需要根據這些屬性重寫物件的hashCode與equals方法即可,
         * 所以重寫了AdminCacheKey類的hashCode和equals方法,這樣,每次訪問的話,就會以每個條件是否相等來判斷物件(即key)是否相等了,這一塊兒的快取就會起作用了
         */
        AdminCacheKey cacheKey = new AdminCacheKey(username, 
                                                   password, 
                                                   start,
                                                   limit);
        List<Admin> adminList = null;
        try {
            System.out.println(cacheKey);
            adminList = adminsCache.get(cacheKey);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return adminList;
    }

    LoadingCache<AdminCacheKey, List<Admin>> adminsCache = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.MINUTES) // 快取項在給定時間內(60min)沒有被寫訪問(建立或覆蓋),則回收
            .maximumSize(100) // 最多快取100項
            .build(new CacheLoader<AdminCacheKey, List<Admin>>() {
                public List<Admin> load(AdminCacheKey key) throws Exception {
                    return adminDao.findAdmin(key.getUsername(),
                                              key.getPassword(), 
                                              key.getStart(), 
                                              key.getLimit());
                }
            });

}

將使用到的兩個方法:

  • public List<Admin> findByUsername(String username)

  • public List<Admin> findAdminList(String username, String password, int start, int limit)

這一塊兒是整個guava cache使用的部分。這裡邊寫出了兩種guava cache使用的方式:

  • 單查詢條件:key為String或Object都可以

  • 多查詢條件:key為Object,該Object封裝了多個查詢條件,並通過這些查詢條件重寫了該Object的hashcode()和equals()

這一部分中guava cache的使用方式,就是實際開發中最常用的方法。




相關文章:
【推薦】 感動到流淚!資料分析師的福音:跨檢視粒度計算