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;
}