1.1 關于Caffeine Cache
? Google Guava Cache是一種非常優秀本地快取解決方案,提供了基于容量,時間和參考的快取回收方式,基于容量的方式內部實作采用LRU演算法,基于參考回收很好的利用了Java虛擬機的垃圾回識訓制,其中的快取構造器CacheBuilder采用構建者模式提供了設定好各種引數的快取物件,快取核心類LocalCache里面的內部類Segment與jdk1.7及以前的ConcurrentHashMap非常相似,都繼承于ReetrantLock,還有六個佇列,以實作豐富的本地快取方案,
? 通俗的講,Guva是google開源的一個公共java庫,類似于Apache Commons,它提供了集合,反射,快取,科學計算,xml,io等一些工具類別庫,cache只是其中的一個模塊,使用Guva cache能夠方便快速的構建本地快取,
? Caffeine是使用Java8對Guava快取的重寫版本,在Spring Boot 2.0中將取代Guava,如果出現Caffeine,
CaffeineCacheManager將會自動配置,
1.1.1 為什么要用本地快取
相對于IO操作
速度快,效率高
相對于Redis
Redis是一種優秀的分布式快取實作,受限于網卡等原因,遠水救不了近火
DB + Redis + LocalCache = 高效存盤,高效訪問
訪問速度和花費的關系如下圖所示:

1.1.2 什么時候用
- 愿意消耗一些記憶體空間來提升速度
- 預料到某些鍵會被多次查詢
- 快取中存放的資料總量不會超出記憶體容量
1.1.3 怎么用
- 設定快取容量
- 設定超時時間
- 提供移除監聽器
- 提供快取加載器
- 構建快取
1.2 使用Caffeine Cache
使用springboot2.x操作Caffeine Cache
搭建工程:Springboot2.x + MyBatis + MySQL + Caffeine Cache
Caffeine是使用Java8對Guava快取的重寫版本,在Spring 5.0或者Spring Boot 2.0中將取代,基于LRU演算法實作,
支持多種快取過期策略,
1.2.1 準備作業
- 準備好資料庫和資料表并插入相應實驗資料(MySQL)
-- 新建表
create database if not exists guavach charset utf8;
-- 使用表
use guavach;
-- 創建用戶表tbl_user
create table tbl_user(
id int(10) not null primary key auto_increment,
name varchar(50) not null,
age int(20) not null
)engine=innodb default charset=utf8;
-- 初始化資料
insert into tbl_user values('1','codesheep.cn','25');
insert into tbl_user values('2','hansongwang99','30');
insert into tbl_user values('3','劉能','35');
insert into tbl_user values('4','趙四','38');
1.2.2 java工程
1.2.2.1 添加依賴
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
1.2.2.2 配置類
引入 CaffeineCache的組態檔 CaffeineCacheConfig
@Configuration
@EnableCaching
public class CaffeineCacheConfig {
@Bean
public CacheManager cacheManager(){
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
//Caffeine配置
Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
//最后一次寫入后經過固定時間過期
.expireAfterWrite(10, TimeUnit.SECONDS)
//maximumSize=[long]: 快取的最大條數
.maximumSize(1000);
cacheManager.setCaffeine(caffeine);
return cacheManager;
}
}
說明:
Caffeine配置說明:
- initialCapacity=[integer]: 初始的快取空間大小
- maximumSize=[long]: 快取的最大條數
- maximumWeight=[long]: 快取的最大權重
- expireAfterAccess=[duration]: 最后一次寫入或訪問后經過固定時間過期
- expireAfterWrite=[duration]: 最后一次寫入后經過固定時間過期
- refreshAfterWrite=[duration]: 創建快取或者最近一次更新快取后經過固定的時間間隔,重繪快取
- weakKeys: 打開key的弱參考
- weakValues:打開value的弱參考
- softValues:打開value的軟參考
- recordStats:開發統計功能
注意: - expireAfterWrite和expireAfterAccess同事存在時,以expireAfterWrite為準,
- maximumSize和maximumWeight不可以同時使用
- weakValues和softValues不可以同時使用
1.2.2.3 組態檔
server:
port: 9020
# Mysql
spring:
datasource:
url: jdbc:mysql://localhost:3306/guavach?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
# mybatis配置
mybatis:
configuration:
map-underscore-to-camel-case: true
#debug: true
1.2.2.4 物體類
public class User implements Serializable {
private static final long serialVersionUID=1L;
private Long id;
private String name;
private Integer age;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
1.2.2.5 mapper
@Mapper
public interface UserMapper {
@Select("select * from tbl_user")
List<User> getUsers();
@Insert("insert into tbl_user values(#{name},#{age})")
int addUser(User user);
@Select("select * from tbl_user where name=#{userName}")
List<User> getUserByName(String userName);
}
1.2.2.6 service
@Service
public class UserService{
@Autowired
private UserMapper userMapper;
public List<User> getUsers() {
return userMapper.getUsers();
}
public int addUser(User user) {
return userMapper.addUser(user);
}
@Cacheable(value = "https://www.cnblogs.com/zifanbg/p/user",key = "#userName")
public List<User> getUserByName(String userName) {
List<User> users=userMapper.getUserByName(userName);
System.out.println("從資料庫中讀取,而非從快取讀取!");
return users;
}
}
說明:在 getUsersByName介面上添加了注解:@Cacheable,這是 快取的使用注解之一,除此之外常用的還有 @CachePut和 @CacheEvit,分別簡單介紹一下:
@Cacheable:配置在getUsersByName方法上表示其回傳值將被加入快取,同時在查詢時,會先從快取中獲取,若不存在才再發起對資料庫的訪問@CachePut:配置于方法上時,能夠根據引數定義條件來進行快取,其與@Cacheable不同的是使用@CachePut標注的方法在執行前不會去檢查快取中是否存在之前執行過的結果,而是每次都會執行該方法,并將執行結果以鍵值對的形式存入指定的快取中,所以主要用于資料新增和修改操作上@CacheEvict:配置于方法上時,表示從快取中移除相應資料,
1.2.2.7 controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@Autowired
CacheManager cacheManager;
@PostMapping("/getuserbyname")
public List<User> getUserByName(@RequestBody User user){
System.out.println("------------");
System.out.println("call /getuserbyname");
List<User> users = userService.getUserByName(user.getName());
return users;
}
@GetMapping("/hehe")
public String hehe(){
return "hehhehhehe";
}
}
1.2.2.8 啟動類
@SpringBootApplication
@EnableCaching//新增注解
public class Caffeinecache01Application {
public static void main(String[] args) {
SpringApplication.run(Caffeinecache01Application.class, args);
}
}
1.3 運行
啟動主類,使用postman測驗
打開postman,輸入json欄位,點擊send按鈕后,顯示回傳結果

查看IDEA控制臺輸出

第一次獲取時,為從資料庫讀取
接著點擊,間隔時間少于10秒,顯示如下結果,可以看到快取的啟用和失效時的效果如下所示(上文 Guava Cache的組態檔中設定了快取 user的實效時間為 10s):

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/147249.html
標籤:Java
上一篇:微服務之間最佳呼叫方式是什么?
下一篇:Electron-vue解決跨域
