SpringBoot+Redis实现数据字典

94 篇文章 6 订阅
68 篇文章 5 订阅

SpringBoot+Redis实现数据字典

前言

我们在日常的开发过程中针对一些字段采用整型的方式去代替某些具体的含义,比如性别0代表男,1代表女。如果只是一些不会变更的转译我们可以采用常量或者枚举类的方式来实现,但是事实上我们也会遇到那种可能需要变更的,显然这种场景下使用枚举类这种方式是不合理的,那么如何动态地去进行转译呢?

正文

数据字典

数据字典Data dictionary)是一种用户可以访问的记录数据库和应用程序元数据的目录。主动数据字典是指在对数据库或应用程序结构进行修改时,其内容可以由DBMS自动更新的数据字典。被动数据字典是指修改时必须手工更新其内容的数据字典。

我们通常会结合数据库来实现数据字典,但事实上数据字典经常会被使用到,如果频繁地去访问数据库,将会对数据库造成性能压力,事实上我们经常会采用Redis对数据字典进行缓存来提升系统性能。

使用Redis的优势:

  1. 绝大数的请求操作都是纯粹的内存操作。
  2. 采用了单线模式,避免了不必要的上下文切换和竞争条件这里的单线程指的是网络请求模块只使用了一个线程(所以不必考虑并发安全性),即一个请求处理所有网络请求,其他模块仍使用了多个线程。
  3. 采用了动态字符串(SDS),对于字符串会预留一定的空间,避免了字符串在做拼接和截取引起内存重新分配导致性能的损耗。

SpringBoot+Redis实现数据字典

依赖

<!--redis-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.9.0</version>
</dependency>
<!--lombok-->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.2</version>
  <optional>true</optional>
</dependency>

application.properties:配置类

#redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

字典表:SYS_DICT

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for SYS_DICT
-- ----------------------------
DROP TABLE IF EXISTS `SYS_DICT`;
CREATE TABLE `SYS_DICT` (
  `code` varchar(36) NOT NULL COMMENT '主键',
  `type_code` varchar(36) DEFAULT NULL COMMENT '类型code',
  `name` varchar(50) DEFAULT NULL COMMENT '展示值',
  `value` int(20) DEFAULT NULL COMMENT '使用值',
  `fixed` int(2) DEFAULT NULL COMMENT 'default 0不固定,固定的话用1',
  `creater` varchar(20) DEFAULT NULL COMMENT '新建人',
  `create_time` datetime DEFAULT NULL COMMENT '新建时间',
  `updater` varchar(20) DEFAULT NULL COMMENT '编辑人',
  `update_time` datetime DEFAULT NULL COMMENT '编辑时间',
  PRIMARY KEY (`code`),
  KEY `sys_type` (`type_code`),
  CONSTRAINT `sys_type` FOREIGN KEY (`type_code`) REFERENCES `SYS_DICT_TYPE` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- ----------------------------
-- Records of SYS_DICT
-- ----------------------------
INSERT INTO `SYS_DICT` VALUES ('182d4db6-aa50-11ea-aa1b-00163e08c9ed', '9ed92c7e-aa4f-11ea-aa1b-00163e08c9ed', '男', '0', '1', null, null, null, null);
INSERT INTO `SYS_DICT` VALUES ('222cf983-aa50-11ea-aa1b-00163e08c9ed', '9ed92c7e-aa4f-11ea-aa1b-00163e08c9ed', '女', '1', '1', null, null, null, null);

字典类型表SYS_DICT_TYPE

SET FOREIGN_KEY_CHECKS=0;


-- ----------------------------
-- Table structure for SYS_DICT_TYPE
-- ----------------------------
DROP TABLE IF EXISTS `SYS_DICT_TYPE`;
CREATE TABLE `SYS_DICT_TYPE` (
  `code` varchar(36) NOT NULL,
  `name` varchar(50) DEFAULT NULL COMMENT '用于展示',
  `value` varchar(50) DEFAULT NULL COMMENT '用于前段(建立唯一索引)',
  `creater` varchar(20) DEFAULT NULL COMMENT '新建人',
  `create_time` datetime DEFAULT NULL COMMENT '新建时间',
  `updater` varchar(20) DEFAULT NULL COMMENT '编辑人',
  `updater_time` datetime DEFAULT NULL COMMENT '编辑时间',
  PRIMARY KEY (`code`),
  UNIQUE KEY `key_value` (`value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- ----------------------------
-- Records of SYS_DICT_TYPE
-- ----------------------------
INSERT INTO `SYS_DICT_TYPE` VALUES ('9ed92c7e-aa4f-11ea-aa1b-00163e08c9ed', '性别', 'sex', null, null, null, null);

RedisConfigurtion:Redis配置类,解决Redis数据同步时字符串格式问题

@Configuration
public class RedisConfigurtion {
    @Autowired
    private RedisTemplate redisTemplate;
    @Bean
    public RedisTemplate<String, Object> stringSerializerRedisTemplate() {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        return redisTemplate;
    }
}

SpringUtil:用于加载Spring容器

@Component
public class SpringUtil implements ApplicationContextAware {


    private static ApplicationContext applicationContext = null;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null){
            SpringUtil.applicationContext  = applicationContext;
        }
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }


    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }


    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

RedisDistUtil:Spring容器不允许普通Pojo调用Service,所以采用以下方式手动通过Spring容器去加载Bean.

public class RedisDistUtil {
    private static ApplicationContext context;
    /**
     * 转化码值
     * @param distname
     * @param value
     * @return
     * @throws Exception
     */
    public static String transformStr(String distname, int value)  {
        ApplicationContext context = SpringUtil.getApplicationContext();
        ISysDictService iSysDictService =context.getBean(ISysDictService.class);
        return iSysDictService.transformStr(distname,value);
    }
}

SysDictService

  • transformStr:从Redis中获取字典值。
  • refreshCache:用于将数据库数据字典表数据同步到Redis中。
@Transactional
@Service
@Slf4j
public class SysDictService implements ISysDictService {

    @Autowired
    SysDictPojoMapper sysDictPojoMapper;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 转化码值
     *
     * @param distname
     * @param value
     * @return
     * @throws Exception
     */
    @Override
    public String transformStr(String distname, int value) {
        return redisTemplate.opsForValue().get(distname + "_" + value) != null ?
               redisTemplate.opsForValue().get(distname + "_" + value).toString() : String.valueOf(value);
    }

    /**
     * 刷新缓存
     */
    @Override
    public void refreshCache() {
        log.info("start 刷新码表缓存");
        List<SysDictPojo> sysDictPojoList = sysDictPojoMapper.getall();
        long startTime = System.currentTimeMillis();
        for (SysDictPojo sysDictPojo : sysDictPojoList) {
            redisTemplate.opsForValue().set(sysDictPojo.getTypeCodeValue() + "_" + sysDictPojo.getValue(), sysDictPojo.getName());
        }
        long endTime = System.currentTimeMillis();
        log.info("end 刷新码表缓存,总计:" + sysDictPojoList.size() + "条,用时:" + (endTime - startTime) + "毫秒");
    }
}

SysDictPojo:数据字典的实体类

@Setter
@Getter
@ToString
public class SysDictPojo implements Serializable {


    private static final long serialVersionUID = 7845051152365224116L;
    private String code;


    private String typeCode;


    private String typeCodeValue;


    private String name;


    private Integer value;


    private Integer fixed;


    private String creater;


    private Date createTime;


    private String updater;


    private Date updateTime;

}

getall:查询数据库的所有数据字典值

<select id="getall" resultType="com.luo.dao.entity.SysDictPojo">
  select
  t1.name,
  t1.value,
  t2.value typeCodeValue
  from SYS_DICT t1
  left join SYS_DICT_TYPE t2 on t2.code =t1.type_code
</select>

验证

UserPojoRes :在get方法里进行数据字典值的替换

@Setter
@Getter
@ToString
public class UserPojoRes implements Serializable {
    private static final long serialVersionUID = -2145503717390503506L;

    /**
     * 主键
     */
    private String id;
    /**
     * 姓名
     */
    private String name;


    /**
     * 性别
     */
    private int sex;


    /**
     * 性别展示
     */
    private String sexStr;


    /**
     * 消息
     */
    private String msg;


    public String getSexStr() {
        return RedisDistUtils.transformStr("sex",this.sex);
    }
}

访问模拟接口,根据id查询用户信息:
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值