文天公寓的缓存优化

Ryder 2023-4-2 25 4/2

描述

基于SpringBoot前后端分离公寓系统,包含移动端和后台管理系统,移动端提供找房、看房
预约、租约管理等功能,后台管理提供房源管理、租赁管理、⽤⼾管理等功能。
技术栈:Spring Boot、MyBatis Plus、Spring MVC、MySQL、Redis、MinIO、Nginx

下载地址:https://gitee.com/chaoge_1998/wentian-apartment-system.git

缓存优化是一个性价比很高的优化手段,多数情况下,缓存优化可以通过一些简单的操作,换来性能的大幅提升。缓存优化的核心思想就是将一些原本保存在磁盘(例如MySQL)中的、经常访问并且查询开销比较大的数据,临时保存到内存(例如Redis)中。后序再访问相同数据时,就可直接从内存中获取结果,而无需再访问磁盘,由于内存的读写速度远高于磁盘,因此就能极大的提高程序的性能。

文天公寓的缓存优化

在使用缓存优化时,有一个问题不得不提,那就是数据库和缓存数据的一致性,当数据库中的数据发生变化时,缓存中的数据也要同步更新,否则就会出现数据不一致的问题,解决该问题的方案有如下几个

  • 数据发生变化时,更新数据库的同时也更新缓存

  • 数据发生变化时,更新数据库的同时删除缓存

在了解了缓存优化的核心思想后,我们以移动端中的根据ID获取房间详情接口为例,进行缓存优化。该接口涉及多表查询,查询时会多次访问数据库,查询代价较高,故可采取缓存优化,加快查询速度。

1.自定义RedisTemplate

本项目使用Reids保存缓存数据,因此我们需要使用RedisTemplate进行读写操作。Spring-data-redis提供了StringRedisTemplateRedisTemplate<Object,Object>两个实例,但是两个实例均不满足我们当前的需求,所以我们需要自定义RedisTemplate。

common模块中创建com.atguigu.lease.common.redis.RedisConfiguration类,内容如下

@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate<String, Object> stringObjectRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.java());
        return template;
    }
}

2.编写缓存逻辑

修改web-app模块中的com.atguigu.lease.web.app.service.impl.RoomInfoServiceImpl中的getDetailById方法,如下

@Override
public RoomDetailVo getDetailById(Long id) {
    String key = RedisConstant.APP_ROOM_PREFIX + id;
    RoomDetailVo roomDetailVo = (RoomDetailVo) redisTemplate.opsForValue().get(key);
    if (roomDetailVo == null) {
        //1.查询房间信息
        ......
        //2.查询图片
        ......
        //3.查询租期
        ......
        //4.查询配套
        ......
        //5.查询标签
        ......
        //6.查询支付方式
        ......
        //7.查询基本属性
        ......
        //8.查询杂费信息
        ......
        //9.查询公寓信息
        ......
        roomDetailVo = new RoomDetailVo();
        ......
        redisTemplate.opsForValue().set(key, roomDetailVo);
    }
    //10.保存浏览历史
    browsingHistoryService.saveHistory(LoginUserHolder.getLoginUser().getUserId(), id);
    return roomDetailVo;
}

3.编写删除缓存逻辑

为保证缓存数据的一致性,在房间信息发生变化时,需要删除相关缓存。

修改web-admin模块中的com.atguigu.lease.web.admin.service.impl.RoomInfoServiceImpl中的saveOrUpdateRoom方法,如下

@Override
public void saveOrUpdateRoom(RoomSubmitVo roomSubmitVo) {
    boolean isUpdate = roomSubmitVo.getId() != null;
    super.saveOrUpdate(roomSubmitVo);
    //若为更新操作,则先删除与Room相关的各项信息列表
    if (isUpdate) {
        //1.删除原有graphInfoList
        ......
        //2.删除原有roomAttrValueList
        ......
        //3.删除原有roomFacilityList
        ......
        //4.删除原有roomLabelList
        ......
        //5.删除原有paymentTypeList
        ......
        //6.删除原有leaseTermList
        ......
        //7.删除缓存
        redisTemplate.delete(RedisConstant.APP_LOGIN_PREFIX + roomSubmitVo.getId());
    }
    //1.保存新的graphInfoList
    ......
    //2.保存新的roomAttrValueList
    ......
    //3.保存新的facilityInfoList
    ......
    //4.保存新的labelInfoList
    ......
    //5.保存新的paymentTypeList
    ......
    //6.保存新的leaseTermList
    ......
}

修改web-admin模块中的com.atguigu.lease.web.admin.service.impl.RoomInfoServiceImpl中的removeRoomById方法,如下

@Override
public void removeRoomById(Long id) {
    //1.删除RoomInfo
    ......
    //2.删除graphInfoList
    ......
    //3.删除attrValueList
    ......
    //4.删除facilityInfoList
    ......
    //5.删除labelInfoList
    ......
    //6.删除paymentTypeList
    ......
    //7.删除leaseTermList
    ......
    //8.删除缓存
    redisTemplate.delete(RedisConstant.APP_ROOM_PREFIX + id);
}

压力测试后,平均响应时间减少30%。

- THE END -

Ryder

4月25日15:38

最后修改:2025年4月25日
2

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论