【Spring Boot系列学习】11.数据存储SQL-缓存的应用

当系统的访问量增大时,相应的数据库的性能就逐渐下降。但是,大多数请求都是在重复的获取相同的数据,如果使用缓存,将结果数据放入其中可以很大程度上减轻数据库的负担,提升系统的响应速度。

声明式缓存

Spring 定义 CacheManager 和 Cache 接口用来统一不同的缓存技术。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 集成 Cache 的时候,我们需要注册实现的 CacheManager 的 Bean。

Spring Boot 为我们自动配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、GuavaCacheConfiguration、RedisCacheConfiguration、SimpleCacheConfiguration 等。所以下面学习中ehcache和redis中无需在配置,若是其他cache,则需先注册。

springboot默认采用ConcurrenMapCacheManager作为缓存管理器,即不使用其他第三方缓存的时候用该类。

 

Spring Boot 针对不同的缓存技术实现了不同的封装,本篇主要介绍 EhCache、Redis和spring cache 缓存。
Spring Boot 提供了以下几个注解实现声明式缓存:

注解说明
@EnableCaching开启缓存功能,放在配置类或启动类上
@CacheConfig缓存配置,设置缓存名称
@Cacheable执行方法前先查询缓存是否有数据。有则直接返回缓存数据;否则查询数据再将数据放入缓存
@CachePut执行新增或更新方法后,将数据放入缓存中
@CacheEvict清除缓存(将一条或多条数据从缓存中删除, 主要用于删除方法,用来从缓存中移除相应数据)
@Caching将多个缓存操作重新组合到一个方法中

1.spring cache

在springboot中默认使用spring cache做缓存。

1.1添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

1.2实现

具体实现与ehcache的实现类似。

2.ehcache缓存

2.1.添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

2.2添加配置

1)在 src/main/resources 目录下创建 ehcache.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir/ehcache"/>
    <!-- 默认缓存 -->
    <defaultCache
            maxEntriesLocalHeap="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxEntriesLocalDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <!-- 自定义缓存 -->
    <cache name="department"
           maxElementsInMemory="1000"
           eternal="false"
           timeToIdleSeconds="50"
           timeToLiveSeconds="50"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

说明

name:Cache 的唯一标识
maxElementsInMemory:内存中允许存储的最大的元素个数
maxElementsOnDisk:硬盘最大缓存个数,0代表无限个
clearOnFlush:内存数量最大时是否清除
eternal:缓存对象是否永久有效,如果是,超时设置将被忽略
overflowToDisk:内存不足(超过 maxElementsInMemory)时,是否启用磁盘缓存
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds:缓存数据的生存时间(TTL),也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间
diskPersistent:是否将缓存数据持久化到磁盘上,如果为 true,JVM 重启数据依然存在。默认值是false
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将根据指定策略清除内存。默认为 LRU(最近最少使用),其他策略有 FIFO(先进先出),LFU(较少使用)

2)application.properties 

# 缓存类型(ehcache、redis)
spring.cache.type=ehcache
# ehcache 配置文件
spring.cache.ehcache.config=classpath:ehcache.xml
# 打印日志,查看 sql
logging.level.com.light.springboot=DEBUG

2.3编码实现

在前面持久化相关教程中的基础上实现。此处采用mybatis基于注解的基础上实现。

即:

1).UserMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bj.study.springboot.dao.UserXmlMapper">
    <insert id="create" parameterType="com.bj.study.springboot.entity.User" >
        INSERT INTO sys_user (id,usercode,username,password,salt,locked) VALUES
        (#{id}, #{usercode}, #{username}, #{password}, #{salt}, #{locked})
    </insert>
    <delete id="deleteByName" parameterType="java.lang.String" >
        DELETE FROM sys_user WHERE username=#{username}
    </delete>
    <delete id="deleteById" parameterType="java.lang.String" >
        DELETE FROM sys_user WHERE id=#{id}
    </delete>
    <select id="getById" parameterType="java.lang.String" resultType="com.bj.study.springboot.entity.User">
        select id,usercode,username,password,salt,locked from sys_user where id = #{id}
    </select>
    <update id="update" parameterType="com.bj.study.springboot.entity.User">
        update sys_user set username = #{username} where id = #{id}
    </update>
</mapper>

2).UserXmlMapper.java(即dao接口)

@Mapper
public interface UserXmlMapper {
    void create(User user);
    User getById(String id);
    void update(User user);
    void deleteById(String id);
}

3).service层

接口

public interface UserService2 {
    User save(User user);
    User update(User user);
    User getUserById(String id);
    void delete(String id);
}

实现类

@CacheConfig(cacheNames = "user")
@Service("userService2")
public class UserServiceImpl2 implements UserService2{

    @Autowired
    private UserXmlMapper userMapper;
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @CachePut(key = "#user.id")
    public User save(User user) {
        logger.info("-------------save start-------------"+"保存 id=" + user.getId() + " 的数据");
        this.userMapper.create(user);
        return user;
    }
    @CachePut(key = "#user.id")
    public User update(User user) {
        logger.info("-------------update start-------------"+"修改 id=" + user.getId() + " 的数据");
        this.userMapper.update(user);
        return user;
    }
    @Cacheable(key = "#id")
    public User getUserById(String id) {
        logger.info("-------------getUserById start-------------"+"获取 id=" + id + " 的数据");
        User user = this.userMapper.getById(id);
        return user;
    }
    @CacheEvict(key = "#id")
    public void delete(String id) {
        logger.info("-------------delete start-------------"+"删除 id=" + id + " 的数据");
        this.userMapper.deleteById(id);
    }
}

4).Controller层

@Controller
@RequestMapping("/user2")
@ResponseBody
public class UserController2 {
    @Autowired
    private UserService2 userService2;
    @RequestMapping("save")
    public Map<String,Object> save(User user) {
        this.userService2.save(user);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code", "200");
        map.put("msg", "保存成功");
        return map;
    }
    @RequestMapping("get/{id}")
    public Map<String,Object> get(@PathVariable("id") String id) {
        User user = this.userService2.getUserById(id);

        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code", "200");
        map.put("msg", "获取成功");
        map.put("data", user);
        return map;
    }
    @RequestMapping("update")
    public Map<String,Object> update(User user) {
        this.userService2.update(user);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code", "200");
        map.put("msg", "修改成功");
        return map;
    }
    @RequestMapping("delete/{id}")
    public Map<String,Object> delete(@PathVariable("id") String id) {
        this.userService2.delete(id);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("code", "200");
        map.put("msg", "删除成功");
        return map;
    }
}

5)启动类:

添加 @EnableCaching 注解,开启缓存功能。

6).启动测试

7).测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserController2Test {
    @Autowired
    private UserController2 controller2;
    @Test
    public void save() throws Exception {
        User user = new User();
        user.setId("test01");
        user.setUsercode("test01");
        user.setUsername("controller测试01");
        user.setPassword("abcdefg");
        user.setLocked("1");
        user.setSalt("abcdefg");
        controller2.save(user);
        System.out.println("-------------保存成功-----------");
        Map map = controller2.get("test01");
        System.out.println( map.get("data"));
    }
    @Test
    public void get() throws Exception {
        Map map = controller2.get("test01");
        System.out.println( map.get("data"));
    }
    @Test
    public void update() throws Exception {
        User user = new User();
        user.setId("test01");
        user.setUsercode("test01");
        user.setUsername("controller测试01");
        user.setPassword("abcdefg");
        user.setLocked("0");
        user.setSalt("abcdefg");
        controller2.update(user);
        System.out.println("-------------更新成功-----------");
        Map map = controller2.get("test01");
        System.out.println( map.get("data"));
    }
    @Test
    public void delete() throws Exception {
        controller2.delete("test01");
        System.out.println("-------------删除成功-----------");
        Map map = controller2.get("test01");
        System.out.println( map.get("data"));
    }
}

此时,依次测试:

1).在save方法中,save成功后,调用controller的get查询方法,其输出日志如下,即没有上面查询所出现的日志。

2).在update方法中,update成功后,调用查询方法,

3).在delete方法中,delete成功后,调用查询方法,执行结果如下:此时有查询日志,且结果为空,说明缓存数据被删除了,需要查询数据库,且查询结果为空。

8).异常

解决方案:

对应的实体类需要进行序列化。

3.Redis 缓存

3.1添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.2添加配置

application.properties 

# redis 配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
# 缓存过期时间,单位毫秒
spring.cache.redis.time-to-live=60000
# 缓存类型(ehcache、redis)
spring.cache.type=redis

3.3后续步骤与ehcache一致。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值