一个简洁的博客网站:http://lss-coding.top,欢迎大家来访
学习娱乐导航页:http://miss123.top/
1. 简介
官方参考地址:https://gitee.com/ld/J2Cache
J2Cache —— 基于内存和 Redis 的两级 Java 缓存框架
J2Cache 是 OSChina 目前正在使用的两级缓存框架(要求至少 Java 8)。第一级缓存使用内存(同时支持 Ehcache 2.x、Ehcache 3.x 和 Caffeine),第二级缓存使用 Redis(推荐)/Memcached 。 由于大量的缓存读取会导致 L2 的网络成为整个系统的瓶颈,因此 L1 的目标是降低对 L2 的读取次数。 该缓存框架主要用于集群环境中。单机也可使用,用于避免应用重启导致的缓存冷启动后对后端业务的冲击。
数据读取
读取顺序 -> L1 -> L2 -> DB
数据更新
1 从数据库中读取最新数据,依次更新 L1 -> L2 ,发送广播清除某个缓存信息
2 接收到广播(手工清除缓存 & 一级缓存自动失效),从 L1 中清除指定的缓存信息
创建一个 Spring Boot 项目,引入缓存所需要的依赖
Spring Boot 版本:2.2.5.RELEASE
org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-cache org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime com.baomidou mybatis-plus-boot-starter 3.5.0 org.springframework.boot spring-boot-starter-test test org.projectlombok lombok 1.18.22 org.junit.jupiter junit-jupiter RELEASE test com.alibaba fastjson 1.2.60 net.oschina.j2cache j2cache-spring-boot2-starter 2.7.6-release net.oschina.j2cache j2cache-core 2.8.2-release org.slf4j slf4j-simple org.slf4j slf4j-api com.alibaba fastjson redis.clients jedis redis.clients jedis 2.9.1 io.lettuce lettuce-core
- 创建一个 student-manager 数据库,创建表 user
CREATE TABLE `user` ( `id` bigint(10) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 在左侧源码部分找到 j2cache-core 包里面的 caffeine.properties、ehcache3.xml、j2cache.properties 三个配置文件复制到 resources 目录下
- application.yml 中配置数据源、redis、j2cache
spring:
datasource:
url: jdbc:mysql://localhost:3306/student-manager?userUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: 49.xxx.xxx.200
port: 6379
cache:
type: none
j2cache:
config-location: /j2cache.properties
redis-client: lettuce
open-spring-cache: true
修改 caffeine.properties 中的 30m 为 30s,这个设置的是一级缓存的过期时间,30s 比较好进行测试修改 j2cache.properties 中的 redis 部分为自己的 redis 服务器的 ip 地址等信息ehcache3.xml 配置文件不需要动
创建 config、domain、mapper、service、impl、controller 各个分层的包,项目虽小,结构不能乱套
创建 FastJsonRedisSerializer 配置 Redis 存储的序列化
public class FastJsonRedisSerializerimplements RedisSerializer { public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private Class clazz; public FastJsonRedisSerializer(Class clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); } }
- 创建 RedisConfig 配置类
@Configuration
@Slf4j
public class RedisConfig {
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Autowired
Environment environment;
@Bean(name = "redisTemplate")
@ConditionalOnMissingBean(RedisTemplate.class)
public RedisTemplate redisTemplate() {
FastJsonRedisSerializer
- 数据库对应的实体类 User
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User implements Serializable{
// 主键 用户id
private Long id;
// 用户名
private String name;
}
- UserMapper 接口
@Mapper public interface UserMapper extends baseMapper{ }
- UserService 接口
public interface UserService {
// 放入缓存
User getUser(Long id);
// 清理缓存中的数据
public User userClear(Long id);
}
- UserServiceImpl 接口实现类
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// 加缓存
@Override
@Cacheable(value = "userInfo", key = "#id")
public User getUser(Long id) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatDate = simpleDateFormat.format(new Date());
System.out.println("访问数据库中的数据!!!" + formatDate);
User user = userMapper.selectById(id);
return user;
}
// 清缓存
@CacheEvict(value = "userInfo", key = "#id")
public User userClear(Long id) {
System.out.println("清理一级缓存中 id:" + id + "的数据");
User user = userMapper.selectById(id);
return user;
}
}
- UserController
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/user/{id}")
public String getUserList(@PathVariable Long id) {
System.out.println("查找id为:" + id + "的用户 " + new Date());
User user = null;
try {
user = userService.getUser(id);
if (user == null) {
return "您查询的用户不在!!!";
}
return user.toString();
} catch (Exception e) {
e.printStackTrace();
return "系统异常,请稍后重试!!!";
}
}
@RequestMapping("/user/clear/{id}")
public String userClear(@PathVariable Long id) {
System.out.println("清楚缓存id为:" + id + "的用户 " + new Date());
User user = null;
try {
user = userService.userClear(id);
} catch (Exception e) {
e.printStackTrace();
return "系统异常,请稍后重试!!!";
}
return user.toString();
}
}
至此测试项目的结构搭建完成
3. 启动项目进行测试- 当项目启动后,我们的一级缓存(jvm中) ehcache3 中是没有任何的缓存数据的,二级缓存 Redis 中也是没有数据的,所以当我们请求接口 http://localhost:8080/user/10001 的时候会先判断一级缓存没有数据,二级缓存没有数据,那么就会查询数据库中的数据来进行回显
Redis 中也会加入数据
- 当我们在数据库中对数据进行了修改的时候,我们再来请求,当一级缓存过期 访问数据库中的数据 的时候,就会进行缓存中数据的更新,同时 二级缓存 Redis 中的数据也会进行更新
这里的测试写的比较乱,大家可以参考上面给出的官方网址进行自行测试,我这里只是一个demo!!!
有什么不对的地方欢迎大家留言



