1、背景
在项目刚刚进入开发阶段设计表时,后期表的字段很可能会增加,可以设计出预留字段来应对。但是假如你的数据数据非常庞大且,那么执行修改表语句时会长时间锁表。而且假如一张表支持许多个客户,每个客户的需求不相同且多变时,使用一张表也无法满足需求。这时可以使用Mysql存储key/value数据满足不同客户需求。
2、Key/Value表设计
以Key/Value存储数据肯定不是Mysql的存储常态,但是可以应对一些灵活多变的场景。以下就是使用Key/Value的例子,先创建要给order订单表,再创建订单表的扩展字段。创建好Key/Value表之后可以为不同的客户配置不同的扩展字段属性和值。
CREATE TABLE `order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text,
`quantity` bigint(20) unsigned DEFAULT NULL COMMENT '数量',
`amount` decimal(22,2) DEFAULT NULL COMMENT '金额',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=337411 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
CREATE TABLE `order_extend` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`order_id` bigint unsigned NOT NULL COMMENT '订单id',
`extendfield_code` varchar(255) NOT NULL COMMENT '扩展字段属性',
`extendfield_value` text COMMENT '扩展字段值',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
3、对象和HashMap相互转化
在设计了Key/Value扩展字段表之后,在某些业务场景为了方便处理扩展字段,可以将对象转化为Map进行操作,一个Map的所有key就是对象的所有字段,value就是对象字段所对应的值。以下是操作Key/Value数据案例操作:
public void example(Long id) {
//查到id对应的订单
Order order = orderMapper.selectByPrimaryKey(id);
//将对象属性转化为map集合
Map<String, Object> map = JSON.parseObject(JSONObject.toJSONString(order), HashMap.class);
//查到对应的扩展字段list
List<OrderExtend> orderExtends = orderExtendMapper.select(id);
for (OrderExtend orderExtend : orderExtends) {
//将扩展字段放入map中
map.put(orderExtend.getExtendFieldCode(),orderExtend.getExtendFieldValue());
}
//......
//对map一顿操作
//......
//将map集合中的数据转化为指定对象的同名属性中
Order updateOrder = JSON.parseObject(JSONObject.toJSONString(map), EventOrder.class);
//更新订单信息
eventOrderMapper.updateByPrimaryKey(updateOrder);
//遍历出map中的扩展字段进行更新
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().startsWith("extendField_")) {
OrderExtend orderExtend = new OrderExtend ();
orderExtend.setOrderId(updateOrder.getId());
orderExtend.setExtendFieldCode(entry.getKey());
orderExtend.setExtendFieldValue(entry.getValue());
update(orderExtend);
}
}
}
- HashMap和对象之间的转化还可以通过使用org.springframework.cglib.beans.BeanMap类中的方法,转化效率高。使用BeanMap进行对象和HashMap的转化:
//将map集合中的数据转化为指定对象的同名属性中
public static <T> Map<String, Object> beanToMap(T bean) {
Map<String, Object> map = new HashMap<>();
if (bean != null) {
BeanMap beanMap = BeanMap.create(bean);
for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
}
return map;
}
//将对象属性转化为map集合
public static <T> T mapToBean(Map map,Class<T> clazz) throws Exception {
T bean = clazz.newInstance();
BeanMap beanMap = BeanMap.create(bean);
beanMap.putAll(map);
return bean;
}