当前位置: 首页 > news >正文

若依字典原理---后端

若依字典原理—后端

数据库设计

在讲解若依字典原理之前先让我们了解一下两个数据库:

1. 字典类型表 (sys_dict_type)

CREATE TABLE sys_dict_type (dict_id     BIGINT PRIMARY KEY,    -- 字典主键dict_name   VARCHAR(100),          -- 字典名称dict_type   VARCHAR(100) UNIQUE,   -- 字典类型(唯一标识)status      CHAR(1) DEFAULT '0',   -- 状态(0正常 1停用)create_by   VARCHAR(64),           -- 创建者create_time DATETIME,              -- 创建时间update_by   VARCHAR(64),           -- 更新者update_time DATETIME,              -- 更新时间remark      VARCHAR(500)           -- 备注
);

2. 字典数据表 (sys_dict_data)

CREATE TABLE sys_dict_data (dict_code   BIGINT PRIMARY KEY,    -- 字典编码dict_sort   INT DEFAULT 0,         -- 字典排序dict_label  VARCHAR(100),          -- 字典标签dict_value  VARCHAR(100),          -- 字典键值dict_type   VARCHAR(100),          -- 字典类型(关联sys_dict_type)css_class   VARCHAR(100),          -- 样式属性list_class  VARCHAR(100),          -- 表格回显样式is_default  CHAR(1) DEFAULT 'N',   -- 是否默认(Y是 N否)status      CHAR(1) DEFAULT '0',   -- 状态(0正常 1停用)create_by   VARCHAR(64),           -- 创建者create_time DATETIME,              -- 创建时间update_by   VARCHAR(64),           -- 更新者update_time DATETIME,              -- 更新时间remark      VARCHAR(500)           -- 备注
);

完整的字典数据流

下图清晰地展示了若依字典数据从创建到使用的完整生命周期:

创建字典类型
sys_dict_type表
创建字典数据
sys_dict_data表
字典类型缓存Redis
字典数据缓存Redis
前端请求字典数据
缓存是否存在?
直接从Redis返回
查询数据库
回填Redis缓存
前端使用字典数据
字典数据变更
清除Redis缓存
下次请求重新加载

核心代码实现

1. 字典数据获取服务

@Service
public class SysDictDataServiceImpl implements ISysDictDataService {@Autowiredprivate RedisCache redisCache;/*** 根据字典类型查询字典数据*/@Overridepublic List<SysDictData> selectDictDataByType(String dictType) {// 1. 首先从Redis缓存获取List<SysDictData> dictDatas = redisCache.getCacheObject(getCacheKey(dictType));if (StringUtils.isNotNull(dictDatas)) {return dictDatas;}// 2. 缓存不存在,查询数据库dictDatas = dictDataMapper.selectDictDataByType(dictType);// 3. 将结果存入Redis缓存if (StringUtils.isNotNull(dictDatas)) {redisCache.setCacheObject(getCacheKey(dictType), dictDatas);}return dictDatas;}/*** 获取缓存Key*/private String getCacheKey(String dictType) {return Constants.SYS_DICT_KEY + dictType;}
}

2. 字典类型服务

@Service
public class SysDictTypeServiceImpl implements ISysDictTypeService {@Autowiredprivate RedisCache redisCache;/*** 根据字典类型查询字典类型信息*/@Overridepublic SysDictType selectDictTypeByType(String dictType) {// 字典类型信息也进行缓存SysDictType dictType = redisCache.getCacheObject(getDictTypeCacheKey(dictType));if (StringUtils.isNotNull(dictType)) {return dictType;}dictType = dictTypeMapper.selectDictTypeByType(dictType);if (StringUtils.isNotNull(dictType)) {redisCache.setCacheObject(getDictTypeCacheKey(dictType.getDictType()), dictType);}return dictType;}
}

3. 缓存清除策略

/*** 字典数据变更时的缓存清理*/
@Override
public int updateDictData(SysDictData dictData) {// 更新数据库int rows = dictDataMapper.updateDictData(dictData);if (rows > 0) {// 清除对应的字典数据缓存redisCache.deleteObject(getCacheKey(dictData.getDictType()));// 同时清除字典类型缓存(如果类型信息有变更)redisCache.deleteObject(getDictTypeCacheKey(dictData.getDictType()));}return rows;
}/*** 删除字典数据时的缓存清理*/
@Override
public int deleteDictDataByIds(Long[] dictCodes) {// 先查询要删除的数据,获取字典类型for (Long dictCode : dictCodes) {SysDictData dictData = dictDataMapper.selectDictDataById(dictCode);if (dictData != null) {// 清除对应字典类型的缓存redisCache.deleteObject(getCacheKey(dictData.getDictType()));}}// 然后删除数据库记录return dictDataMapper.deleteDictDataByIds(dictCodes);
}

前端调用流程

1. 字典数据获取接口

@RestController
@RequestMapping("/system/dict/data")
public class SysDictDataController {/*** 根据字典类型查询字典数据信息*/@GetMapping(value = "/type/{dictType}")public AjaxResult dictType(@PathVariable String dictType) {// 这个接口就是前端组件调用的核心接口List<SysDictData> data = dictDataService.selectDictDataByType(dictType);return AjaxResult.success(data);}
}

2. 前端调用方式

// 1. 组件中声明字典依赖
export default {dicts: ['sys_user_sex', 'sys_normal_disable'],created() {// 2. 字典数据自动加载到 this.dict.typeconsole.log(this.dict.type.sys_user_sex);// 输出: [{ dictLabel: '男', dictValue: '0' }, { dictLabel: '女', dictValue: '1' }]}
}

缓存键设计

若依框架使用统一的缓存键格式:

public class Constants {/*** 字典管理 cache key*/public static final String SYS_DICT_KEY = "sys_dict:";/*** 字典类型 cache key  */public static final String SYS_DICT_TYPE_KEY = "sys_dict_type:";
}
  • 字典数据缓存键: sys_dict:${dictType}
    例如: sys_dict:sys_user_sex

  • 字典类型缓存键: sys_dict_type:${dictType}
    例如: sys_dict_type:sys_user_sex

设计优势

  1. 性能优化: 避免频繁查询数据库,提升响应速度
  2. 数据一致性: 通过缓存清除机制保证数据及时更新
  3. 系统解耦: 字典数据与业务逻辑分离,便于维护
  4. 通用性: 统一的字典管理,全系统共享使用

注意事项

  1. 缓存时效: 若依通常设置缓存永不过期,依靠更新时的清除机制
  2. 内存管理: 大量字典数据需要考虑Redis内存使用
  3. 集群环境: 在集群部署时,确保所有节点缓存同步

这种设计确保了字典数据的高效访问,同时通过合理的缓存策略保证了数据的实时性和一致性。

字典缓存详细机制

大家在使用的若依的时候会发现在redis中有sys:dict:* 数据,你很容易会想到他是字典缓存,但是当你去查询字典的 增删改查 的时候会发现只有一个接口使用了redis做缓存去返回值。
此方法如下:

    /*** 根据字典类型查询字典数据信息*/@GetMapping(value = "/type/{dictType}")public AjaxResult dictType(@PathVariable String dictType){List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);if (StringUtils.isNull(data)){data = new ArrayList<SysDictData>();}return success(data);}

再去深入了解会发现此接口便是我们组件调用字典返回值的接口,这时也可能会有一个疑问为什么若依不去将其他的接口做缓存处理?

若依框架的字典缓存设计,确实是有意识地区分了“高频常量型”数据和“低频管理型”数据。下面这个表格能帮你清晰理解这种设计思路的核心区别:

特性维度带缓存的字典接口 (如 getDicts)普通查询接口 (如字典列表分页查询)
核心场景前端组件渲染、数据回显等高频读取场景后台系统的字典管理功能(增删改查)
数据特性稳定字典数据 (如 “用户状态”,"性别"等,定义后很少变更)任何字典数据,包括其当前状态、分页列表等
性能要求,要求快速响应,避免重复数据库查询相对较低,管理操作频率远低于前端数据展示
缓存机制查询时优先读取Redis缓存,无缓存则查库并回填通常直接查询数据库
数据一致性通过字典数据变更时清除对应缓存来保证实时查询,天然保持一致性

为何这样设计

若依框架这样设计字典缓存,主要基于以下几点考虑:

  1. 性能与资源平衡
    框架将珍贵的缓存资源(如Redis内存)用在刀刃上,即那些最常用、最影响用户体验的字典数据。这避免了为所有字典查询都建立和维护缓存带来的额外开销。

  2. 保证管理操作的实时性
    在后台管理字典时,必然希望任何增、删、改操作都能立刻看到准确结果。如果这些管理类查询也走缓存,就需要在数据变更时维护更多缓存,增加数据不一致的风险(比如改了字典值但缓存更新不及时)。

  3. 简化缓存策略
    只为最核心的接口配置缓存,使得缓存的失效和更新策略变得简单明确:主要关注字典数据本身的变更即可。

深入了解缓存机制

若依框架中字典缓存的核心运作方式,尤其是针对那个带缓存的接口,可以概括为以下几点:

  • 缓存键与类型:缓存通常以字典类型dict_type)为关键维度。例如,接口根据传递过来的字典类型首先从Redis的字典缓存中查询。
  • 数据更新与缓存清除:当你在后台修改字典数据时,若依框架会清除对应字典类型的Redis缓存。这样下次通过 getDicts 接口请求时,缓存未命中,就会从数据库查询最新数据并重新写入缓存,从而保证前端能获取到最新数据。

注意事项

了解上述机制后,在实际开发和维护中需要注意:

  • 新增字典数据不显示:向已有字典类型新增数据后,前端若未显示,通常是因为旧的字典数据仍在缓存中。此时需要清除Redis中对应的字典缓存(例如通过系统提供的缓存监控功能或手动清除),触发下次查询时重新加载。
  • 空字典缓存问题:早期的若依版本可能存在一个情况:如果仅为字典类型创建了类型但未添加具体数据,可能导致缓存了空集合,之后即使添加了数据,由于空缓存的存在,接口仍返回空。这一问题在后续版本中已修复。

总结

若依框架选择只为特定字典接口(如 getDicts)使用缓存,是经过权衡的:优先保障高频、稳定数据访问的性能,同时确保管理操作的实时性和数据一致性,并简化缓存管理。这种设计在多数情况下是合理且高效的。

希望这些解释能帮助你更好地理解若依字典缓存的设计,并指导你的开发和问题排查。

http://www.dtcms.com/a/503149.html

相关文章:

  • SpringBoot 接入 Prometheus + Grafana
  • 自己有网站怎么做优化实时热榜
  • 基于SpringBoot的“基于数据安全的旅游民宿租赁系统”的设计与实现(源码+数据库+文档+PPT)
  • 海宁公司做网站wordpress编辑器存内容
  • 旅游管理系统|基于SpringBoot和Vue的旅游管理系统(源码+数据库+文档)
  • DAQ系统混合方案与设计模式详解
  • 【Linux系统编程】3. Linux基本指令(下)
  • sql练习-5
  • 做网站审批号必须要wix做网站的建议
  • YAML的Value表示
  • 如何在Gitee和GitHub上部署SSH公钥
  • 成都高新网站建设美图秀秀在线制作
  • Flutter Isolate的使用
  • 从 JDK 8 到 JDK 23:HotSpot 垃圾回收器全景演进与深度剖析
  • 深圳网站建设jm3q网站是公司域名是个人可以吗
  • 【深度学习新浪潮】多模态大模型在图像理解领域的技术进展与实践
  • wordpress 分类菜单高亮外贸seo软件
  • 百度面试题解析:Zookeeper、ArrayList、生产者消费者模型及多线程(二)
  • excel绘制折线图
  • 数据结构(c++版):二叉树的实现
  • 厦门手机网站建设wordpress mkv格式
  • spiderdemo题解系列——第2篇:请求头检测挑战(第1题)
  • 数据事件及数据查询——东方财富掘金量化速成学习(python)
  • 数据库做网站wordpress ip地址
  • 上海做网站及推广网站关键词怎么优化
  • 利用汽车雷达测试系统模拟多径效应——论文阅读
  • 【大语言模型】—— 自注意力机制及其变体(交叉注意力、因果注意力、多头注意力)的代码实现
  • TensorFlow2 Python深度学习 - 生成对抗网络(GAN)简介
  • 珠海网站品牌设计公司简介厦门网页
  • 房子网站有哪些在线企业查询系统