自命为缓存之王的Caffeine(4)

时间:2023-02-13 19:13:03

您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~




说了很多Caffeine的基本特性,但是骡子是马,终归还是要看能不能拉磨。SpringBoot有两种使用Caffeine的方式:

1、直接引入Caffeine依赖,然后使用Caffeine方法实现缓存;

2、引入Caffeine和Spring Cache依赖,使用注解方式实现缓存。

先实现第一种方式(之前已实现过,整合到SpringBoot),这种方式比较灵活。再使用第二种方式(用注解实现Caffeine缓存功能),这种方式比较方便。

先引入依赖:

<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>

在配置文件中加入(这是可选的):

## CAFFEINE
customer.caffeine.initialCapacity=50
customer.caffeine.maximumSize=500
customer.caffeine.expireAfterWrite=86400

声明注入代码:

/**
* 声明注入代码
*
* @author 湘王
*/
@Configuration
@Component
public class WebConfiguration extends WebMvcConfigurationSupport {
/**
* 进程外缓存初始化
*
*/
@Bean("cache")
public LoadingCache<String, String> cache() {
return Caffeine.newBuilder()
.initialCapacity(1024)
.maximumSize(1024)
.expireAfterWrite(1, TimeUnit.HOURS)
.build(key -> {
return "";
});
}
}

然后在代码中调用:

/**
* 功能描述
*
* @author 湘王
*/
public class CaffeineTest {
@Resource
private LoadingCache<String, String> cache;

/**
* 保存缓存数据
*
*/
public void setCache(final String key, final String value) {
cache.put(key, value);
}

/**
* 读取缓存数据
*
*/
public String getCache(final String key) {
return cache.get(key);
}

/**
* 清除缓存数据
*
*/
public void clearCache(final String key) {
cache.invalidate(key);
}
}


然后再来看看第二种方式。先引入依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>

在属性文件中加入配置:

## CAFFEINE
spring.cache.cache-names=test
spring.cache.type=caffeine
spring.cache.caffeine.spec=initialCapacity=50,maximumSize=500,expireAfterWrite=300s

定义一个实体类(之前用过的类):

/**
* 用户entity
*
* @author 湘王
*/
public class SysUser implements Serializable, RowMapper<SysUser> {
private static final long serialVersionUID = -1214743110268373599L;

private int id;
private int bid;
private String username;
private String password;
private int scope; // 0:全部,1:部门及以下,2:仅个人
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
protected Date createtime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
protected Date updatetime;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getBid() {
return bid;
}

public void setBid(int bid) {
this.bid = bid;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

@JsonIgnore
public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public int getScope() {
return scope;
}

public void setScope(int scope) {
this.scope = scope;
}

public Date getCreatetime() {
return createtime;
}

public void setCreatetime(Date createtime) {
this.createtime = createtime;
}

public Date getUpdatetime() {
return updatetime;
}

public void setUpdatetime(Date updatetime) {
this.updatetime = updatetime;
}

@Override
public SysUser mapRow(ResultSet result, int i) throws SQLException {
SysUser user = new SysUser();

user.setId(result.getInt("id"));
user.setUsername(result.getString("username"));
user.setPassword(result.getString("password"));
user.setCreatetime(result.getTimestamp("createtime"));
user.setUpdatetime(result.getTimestamp("updatetime"));

return user;
}
}


然后定义服务类:

/**
* 缓存服务
*
* @author 湘王
*/
@Service
public class CaffeineService {
/**
* 将新增的用户信息放入缓存
*
*/
@CachePut(value = "test", key = "#id")
public int addUser(int id, String username, String password) {
String sql = "";
// TODO SOMETHING
return -1;
}

/**
* 从缓存读取用户信息,id作为key
*
*/
@Cacheable(value = "test", key = "#id")
public SysUser queryById(int id) {
System.out.println("从数据库读取:" + id);
String sql = "";
// TODO SOMETHING
return new SysUser();
}

/**
* 从缓存读取用户信息,username作为key
*
*/
@Cacheable(value = "test", key = "#username")
public SysUser queryByUsername(String username) {
System.out.println("从数据库读取:" + username);
String sql = "";
// TODO SOMETHING
return new SysUser();
}
}

再定义Contorller类:

/**
* 缓存COntroller
*
* @author 湘王
*/
@RestController
public class CacheController {
@Resource
private CaffeineService caffeineService;

/**
* 添加用户
*
*/
@PostMapping("/user/add")
public String add(int id, String username, String password) {
caffeineService.addUser(id, username, password);
return "添加用户成功";
}

/**
* 查询用户
*
*/
@GetMapping("/user/id")
public String id(int id) {
SysUser user = caffeineService.queryById(id);
return "查询到用户:" + user.getUsername();
}

/**
* 查询用户
*
*/
@GetMapping("/user/username")
public String username(String username) {
SysUser user = caffeineService.queryByUsername(username);
return "查询到用户:" + user.getUsername();
}
}


先添加用户,再分别通过ID和用户名查询,可以看到:

1、第一次查询,会从数据库中读取;

2、第二次查询,就直接从Caffeine中读取了。

当超过设定的300s后,再次读取又会从数据中查询。

使用注解的方式简单、快速,但注解缺点是不能灵活操控,如异步存储和无法查看统计信息。



感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~