spring通过注解为我们提供了缓存功能,默认使用Ehcache
,当然,也可以配置用其它的方式缓存,如redis, memcache,它主要是提高数据的查询效率。
在Spring的@Cache注解中,管理的是一个Map1<name, Map2<key, value>>的存储结构,Map1对应的是CacheManager实现,Map2对应的是Cache实现,在实现中CacheManager和Cache都可以通过配置的方式,实现不同的缓存策略,如下图:
spring-cache.png
主要应用了策略模式【面向接口,而不是面向实现
】实现业务与具体实现的隔离;通过具体的不同策略实现【开闭原则】,可以方便的增加多个具体实现;业务代码只依赖接口,不依赖具体的实现【依赖倒转原则】,高层的业务模块不依赖底层的具体算法。
下面,我们通过redis实现缓存。
首先导入相关包:
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-data-redis')
compile('org.apache.commons:commons-pool2')
在主引导类上添加注解,打开缓存,如下:
@EnableCaching
@SpringBootApplication
public class Chapter08Application {
接着编写配置文件,指定缓存类型是redis(先启动本地redis服务
)
spring:
datasource:
url: jdbc:mysql://localhost:3306/xfdb?useUnicode=true&characterEncoding=UTF-8
password: root
username: root
redis:
host: 127.0.0.1
#password:
cache:
type: redis #指定spring默认cache
timeout: 1000
database: 0 #默认有16个分片,这里配置具体使用的分片,默认是0
lettuce:
pool:
max-active: 8 #最大连接数(使用负值表示没有限制) 默认 8
max-wait: -1 #最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-idle: 8 #最大空闲连接 默认 8
min-idle: 0
定义vo对象,如下:
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
private String email;
public User() {
}
public User(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
...
接着定义接口,因为cache使用的是策略模式(一定要使用接口
),如下:
public interface UserService {
/**
* 添加更新
*/
User saveOrUpdate(User user);
/**
* 查询
*/
User get(Long id);
/**
* 删除
*/
void delete(Long id);
}
接着,定义一个接口实现类,模拟实现从DB读取数据,若有缓存则从缓存获取,如下:
@Service
public class UserServiceImpl implements UserService {
//模拟db存储数据
private static final Map<Long, User> DATABASES = new HashMap<>();
//数据初始化
static {
DATABASES.put(1L, new User(1L, "jack", 22));
DATABASES.put(2L, new User(2L, "andy", 23));
DATABASES.put(3L, new User(3L, "mack", 24));
}
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
@Cacheable(value = "user", key = "#id")
public User get(Long id) {
// 若缓存无数据,则会打印log,同时会将数据添加到缓存
log.info("==============> get() ");
return DATABASES.get(id);
}
@CachePut(value = "user", key = "#user.id", condition = "#user.name.length() < 10")
public User saveOrUpdate(User user) {
//添加或更新数据到缓存,可以设置数据的条件
log.info("==============> saveOrUpdate() ");
DATABASES.put(user.getId(), user);
return user;
}
@CacheEvict(value = "user", key = "#id", allEntries = true, beforeInvocation = true)
public void delete(Long id) {
//删除缓存中数据
log.info("===============> delete()");
DATABASES.remove(id);
}
}
我们可以依次调用saveOrUpdate--->get---->delete---->get,查看缓存数据,当第一次调用时,会打log,说明进入了该方法,即查了db,若缓存中有数据则get不会输出log。
学习交流,请加群:64691032
网友评论