Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] 的存储,也就是说其他数据结构的Value一般是确切的值,而Hash的Value是一系列的键值对。
通常我们是这样称呼Hash的存储的:大Key为实际的Key,小Key为Field,而具体的取值为Field对应的值value
实践:系统数据字典实时触发缓存存储
2.1 在数据库建立 系统字典 表 sys_dict_config
CREATE TABLE `sys_dict_config` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典类型',
`name` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典名称',
`code` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项编码',
`value` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项取值',
`order_by` int(11) DEFAULT '1' COMMENT '排序',
`is_active` int(11) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
`create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_type_code` (`type`,`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.2 新建实体类 SysDictConfig,SysDictConfigMapper,SysDictConfigMapper.xml,代码如下:
SysDictConfig:
package com.example.redislearn.entity;
import org.hibernate.validator.constraints.NotBlank;
import java.io.Serializable;
import java.util.Date;
public class SysDictConfig implements Serializable {
private Integer id;
@NotBlank(message = "字典类型不能为空")
private String type;
@NotBlank(message = "字典名称不能为空")
private String name;
@NotBlank(message = "选项编码不能为空")
private String code;
@NotBlank(message = "选项取值不能为空")
private String value;
//排序
private Integer orderBy;
//是否有效(1=是;0=否)
private Byte isActive=1;
//创建时间
private Date createTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Integer getOrderBy() {
return orderBy;
}
public void setOrderBy(Integer orderBy) {
this.orderBy = orderBy;
}
public Byte getIsActive() {
return isActive;
}
public void setIsActive(Byte isActive) {
this.isActive = isActive;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
SysDictConfigMapper:
package com.example.redislearn.dao;
import com.example.redislearn.entity.SysDictConfig;
import java.util.List;
public interface SysDictConfigMapper {
int deleteByPrimaryKey(Integer id);
int insert(SysDictConfig sysDictConfig);
int insertSelective(SysDictConfig sysDictConfig);
SysDictConfig selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(SysDictConfig sysDictConfig);
int updateByPrimaryKey(SysDictConfig sysDictConfig);
List selectActiveConfigs();
}
SysDictConfigMapper.xml:
id, type, name, code, value, order_by, is_active, create_time
delete from sys_dict_config
where id = #{id,jdbcType=INTEGER}
insert into sys_dict_config (id, type, name,
code, value, order_by,
is_active, create_time)
values (#{id,jdbcType=INTEGER}, #{type,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{code,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR}, #{orderBy,jdbcType=INTEGER},
#{isActive,jdbcType=TINYINT}, #{createTime,jdbcType=TIMESTAMP})
insert into sys_dict_config
id,
type,
name,
code,
value,
order_by,
is_active,
create_time,
#{id,jdbcType=INTEGER},
#{type,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR},
#{code,jdbcType=VARCHAR},
#{value,jdbcType=VARCHAR},
#{orderBy,jdbcType=INTEGER},
#{isActive,jdbcType=TINYINT},
#{createTime,jdbcType=TIMESTAMP},
update sys_dict_config
type = #{type,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
code = #{code,jdbcType=VARCHAR},
value = #{value,jdbcType=VARCHAR},
order_by = #{orderBy,jdbcType=INTEGER},
is_active = #{isActive,jdbcType=TINYINT},
create_time = #{createTime,jdbcType=TIMESTAMP},
where id = #{id,jdbcType=INTEGER}
update sys_dict_config
set type = #{type,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
code = #{code,jdbcType=VARCHAR},
value = #{value,jdbcType=VARCHAR},
order_by = #{orderBy,jdbcType=INTEGER},
is_active = #{isActive,jdbcType=TINYINT},
create_time = #{createTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=INTEGER}
2.3 RedisHashController类 ,代码如下:
package com.example.redislearn.controller;
import com.example.redislearn.entity.SysDictConfig;
import com.example.redislearn.response.BaseResponse;
import com.example.redislearn.response.StatusCode;
import com.example.redislearn.service.RedisHashService;
import com.example.redislearn.util.ValidatorUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 数据类型Hash字典
* Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,
* 而Hash则是:Key – [Field-Value] 的存储,也就是说其他数据结构的Value一般是确切的值,而Hash的Value是一系列的键值对,
* 通常我们是这样称呼Hash的存储的:大Key为实际的Key,小Key为Field,而具体的取值为Field对应的值value。
* 实践:系统数据字典实时触发缓存存储
*/
/**
* 常用的方法:
* 1. put(H key, HK hashKey, HV value); 新增hashMap值。
* 2. putAll(H key, Map extends HK,? extends HV> m);以map集合的形式添加键值对。
* 3. entries(H key); 获取key的列表元素。
* 4. get(H key, Object hashKey); 获取变key中的指定field键是否有值,如果存在返回value,没有则返回null。
* 5. keys(H key); 获取key中的所有field列表。
* 6. hasKey(H key, Object hashKey);判断key是否有指定的field。
* 7. delete(H key, Object... hashKeys); 删除key中的field-value对,可以传入多个参数,删除多个field-value对。
* 8. size(H key);获取key的长度。
*/
@RestController
@RequestMapping("RedisHashController")
public class RedisHashController {
private static final Logger log = LoggerFactory.getLogger(RedisHashController.class);
@Autowired
private RedisHashService redisHashService;
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping(value = "/hashSet", method = RequestMethod.POST)
public void hashSet() {
log.info("----开始哈希Hash测试");
final String key = "SpringBootRedis:Hash:Key:英雄联盟";
redisTemplate.delete(key);
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put(key, "德玛西亚", "盖伦");
hashOperations.put(key, "诺克萨斯", "德莱厄斯");
Map dataMap = Maps.newHashMap();
dataMap.put("祖安", "蒙多");
dataMap.put("艾欧尼亚", "艾瑞莉娅");
hashOperations.putAll(key, dataMap);
log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));
log.info("---哈希hash-获取诺克萨斯的元素: {} ", hashOperations.get(key, "诺克萨斯"));
log.info("---哈希hash-获取所有元素的field列表: {} ", hashOperations.keys(key));
log.info("---哈希hash-祖安成员是否存在: {} ", hashOperations.hasKey(key, "祖安"));
log.info("---哈希hash-艾欧尼亚成员是否存在: {} ", hashOperations.hasKey(key, "艾欧尼亚"));
hashOperations.putIfAbsent(key, "暗影", "卡尔萨斯");
log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));
log.info("---哈希hash-删除元素德玛西亚、 诺克萨斯: {} ", hashOperations.delete(key, "德玛西亚", "诺克萨斯"));
log.info("---哈希hash-获取列表元素: {} ", hashOperations.entries(key));
log.info("---哈希hash-获取列表元素个数: {} ", hashOperations.size(key));
}
//==============================================系统数据字典实时触发缓存存储=================================================//
/**
* 添加数据字典及其对应的选项(field-value)
* @param config
* @param result
* @return
*/
@RequestMapping(value = "/addSysDictConfig",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public BaseResponse addSysDictConfig(@RequestBody @Validated SysDictConfig config, BindingResult result){
String checkRes= ValidatorUtil.checkResult(result);
/*if (StringUtils.isNotBlank(checkRes)){
return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
}*/
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
redisHashService.addSysDictConfig(config);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
/**
*获取缓存中所有的数据字典
* @return
*/
@RequestMapping(value = "getSysDictConfig",method = RequestMethod.GET)
public BaseResponse getSysDictConfig(){
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
response.setData(redisHashService.getSysDictConfig());
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
/**
* 获取缓存中某个特定编码下数据字典的取值列表
* @param type
* @return
*/
@RequestMapping(value = "get/type",method = RequestMethod.GET)
public BaseResponse getType(@RequestParam String type){
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
response.setData(redisHashService.getByType(type));
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
}
2.4 业务类:RedisHashService,代码如下:
package com.example.redislearn.service;
import com.example.redislearn.dao.SysDictConfigMapper;
import com.example.redislearn.entity.SysDictConfig;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
@Service
public class RedisHashService {
private static final Logger log = LoggerFactory.getLogger(RedisHashService.class);
private static final String RedisHashKey = "Redis:Hash";
@Autowired
private SysDictConfigMapper sysDictConfigMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
* 添加数据字典及其对应的选项(code-value)
*
* @param config
* @return
* @throws Exception
*/
@Transactional(rollbackFor = Exception.class)
public Integer addSysDictConfig(SysDictConfig config) throws Exception {
int res = sysDictConfigMapper.insertSelective(config);
if (res > 0) {
//实时触发数据字典的hash存储
cacheConfigMap();
}
return config.getId();
}
/**
* 取出缓存中所有的数据字典列表
*/
public Map> getSysDictConfig() throws Exception {
return getAllCacheConfig();
}
/**
* 取出缓存中特定的数据字典列表
*
* @param type
* @return
* @throws Exception
*/
public List getByType(final String type) throws Exception {
return getCacheConfigByType(type);
}
/**
* 实时获取所有有效的数据字典列表-转化为map-存入hash缓存中
*/
@Async
public void cacheConfigMap() {
try {
List sysDictConfigList = sysDictConfigMapper.selectActiveConfigs();
if (sysDictConfigList != null && !sysDictConfigList.isEmpty()) {
Map> dataMap = Maps.newHashMap();
//所有的数据字典列表遍历 -> 转化为 hash存储的map
sysDictConfigList.forEach(sysDictConfig -> {
List list = dataMap.get(sysDictConfig.getType());
if (CollectionUtils.isEmpty(list)) {
list = Lists.newLinkedList();
}
list.add(sysDictConfig);
dataMap.put(sysDictConfig.getType(), list);
});
//存储到缓存hash中
HashOperations> hashOperations = redisTemplate.opsForHash();
hashOperations.putAll(RedisHashKey, dataMap);
}
} catch (Exception e) {
log.error("实时获取所有有效的数据字典列表-转化为map-存入hash缓存中-发生异常:", e.fillInStackTrace());
}
}
/**
* 从缓存hash中获取所有的数据字典配置map
*
* @return
*/
public Map> getAllCacheConfig() {
Map> map = Maps.newHashMap();
try {
HashOperations> hashOperations = redisTemplate.opsForHash();
map = hashOperations.entries(RedisHashKey);
} catch (Exception e) {
log.error("从缓存hash中获取所有的数据字典配置map-发生异常:", e.fillInStackTrace());
}
return map;
}
/**
* 从缓存hash中获取特定的数据字典列表
*
* @param type
* @return
*/
public List getCacheConfigByType(final String type) {
List list = Lists.newArrayList();
try {
HashOperations> hashOperations = redisTemplate.opsForHash();
list = hashOperations.get(RedisHashKey, type);
} catch (Exception e) {
log.error("从缓存hash中获取特定的数据字典列表-发生异常:", e.fillInStackTrace());
}
return list;
}
}
启动项目
测试 添加数据字典及其对应的选项(field-value)
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/addSysDictConfig
post请求
测试 获取缓存中所有的数据字典 功能:
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/getSysDictConfig
get请求
测试 获取缓存中某个特定编码下数据字典的取值列表 功能:
在浏览器或postman 上输入:http://127.0.0.1:8782/RedisHashController/get/type?type=sex
get请求