千家信息网

Mybatis中怎么样操作mysql8的Json字段类型

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章主要介绍Mybatis中怎么样操作mysql8的Json字段类型,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Json字段是从mysql 5.7起加进来的全新的字段类型
千家信息网最后更新 2025年02月01日Mybatis中怎么样操作mysql8的Json字段类型

这篇文章主要介绍Mybatis中怎么样操作mysql8的Json字段类型,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Json字段是从mysql 5.7起加进来的全新的字段类型,现在我们看看在什么情况下使用该字段类型,以及用mybatis如何操作该字段类型

一般来说,在不知道字段的具体数量的时候,使用该字段是非常合适的,比如说--商品的无限属性。

现在我们来假设这么一个场景,在商品的二级分类中给商品定义足够多的属性,我们先设计属性的类

/** * 商品自定义属性 */@NoArgsConstructor@AllArgsConstructorpublic class OtherProperty implements Serializable {@Getter    @Setter    private Long id; //属性id    @Getter    @Setter    private FormType formType; //前端使用的表单类型    @Getter    @Setter    private String name; //属性名称    @Getter    @Setter    private String unit; //单位    @Getter    @Setter    private String values; //可选值以@分隔,如配件@车品    @Getter    private List valueList = new ArrayList<>(); //对可选值的取值列表    @Getter    @Setter    private String defaultValue; //可选值中的默认值    @Getter    @Setter    private boolean search; //是否可搜索    @Getter    @Setter    private boolean mustWrite; //是否必录    @Getter    @Setter    private Boolean used = false; //是否已经在商品中使用,已使用该属性则不允许修改    public OtherProperty changeValuesToList() {        String[] split = this.values.split("@");        for (String value : split) {this.valueList.add(value);        }this.values = null;        return this;    }@Override    public boolean equals(Object o) {if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        OtherProperty that = (OtherProperty) o;        if (!id.equals(that.id)) return false;        if (search != that.search) return false;        if (mustWrite != that.mustWrite) return false;        if (formType != that.formType) return false;        if (!name.equals(that.name)) return false;        if (unit != null ? !unit.equals(that.unit) : that.unit != null) return false;        if (values != null ? !values.equals(that.values) : that.values != null) return false;        return defaultValue != null ? defaultValue.equals(that.defaultValue) : that.defaultValue == null;    }@Override    public int hashCode() {int result = id.hashCode() + formType.hashCode() + name.hashCode();        result = result + (unit != null ? unit.hashCode() : 0);        result = result + (values != null ? values.hashCode() : 0);        result = result + (defaultValue != null ? defaultValue.hashCode() : 0);        result = result + (search ? 1 : 0);        result = result + (mustWrite ? 1 : 0);        return result;    }}

其中formType为枚举类型

public enum FormType implements Localisable {TYPE1("文本框"),    TYPE2("下拉框"),    TYPE3("单选框"),    TYPE4("复选框"),    TYPE5("多行文本框");    private String value;    private FormType(String value) {this.value = value;    }@Override    public String getValue() {return this.value;    }}

我们来看一下商品分类的部分代码

@AllArgsConstructor@NoArgsConstructorpublic class ProviderProductLevel implements Provider,Serializable

其中包含一个商品属性对象的列表

@Getter@Setterprivate List otherProperties;

部分操作源码如下

/** * 通过二级配件分类id查找其包含的所有其他属性 * @param * @return */public List findOtherProperties() {if (this.level == 2) {        LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class);        String ids = levelDao.findIdsByLevel2Id(this.id);        return levelDao.findOtherProperties(ids);    }return null;}/** * 在二级配件分类中删除其他属性的id * @param paramIds * @return */public boolean deletePropertyIdfromLevel(String paramIds) {if (this.level == 2) {        LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class);        String ids = levelDao.findIdsByLevel2Id(this.id);        String[] idsArray = ids.split(",");        List idsList = Arrays.asList(idsArray);        List contentIdsList = new ArrayList<>();        contentIdsList.addAll(idsList);        String[] paramArray = paramIds.split(",");        List paramList = Arrays.asList(paramArray);        if (contentIdsList.containsAll(paramList)) {            contentIdsList.removeAll(paramList);        }if (contentIdsList.size() > 0) {            StringBuilder builder = new StringBuilder();            contentIdsList.stream().forEach(eachId -> builder.append(eachId + ","));            String newIds = builder.toString().substring(0, builder.toString().length() - 1);            levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId(newIds, this.id));        }else {            levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId("",this.id));        }return true;    }return false;}
/** * 展示某二级配件分类的所有其他属性 * @param id * @return */@SuppressWarnings("unchecked")@Transactional@GetMapping("/productprovider-anon/showproperties")public Result> showOtherProperties(@RequestParam("id") Long id) {    Provider level2 = levelDao.findLevel2(id);    return Result.success(((ProviderProductLevel)level2).findOtherProperties());}/** * 修改某二级配件分类的其他属性 * @param id * @param otherProperties * @return */@SuppressWarnings("unchecked")@Transactional@PostMapping("/productprovider-anon/changeother")public Result changeOtherProperties(@RequestParam("id") Long id,@RequestBody List otherProperties) {//获取配件二级分类对象    Provider level2 = levelDao.findLevel2(id);    //获取未使用的配件二级分类的其他属性(没有任何商品使用过该属性)    List unUsedList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream())            .orElse(new ArrayList().stream())            .filter(otherProperty -> !otherProperty.getUsed())            .collect(Collectors.toList());    //获取已使用的配件二级分类的其他属性    List usedIdList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream())            .orElse(new ArrayList().stream())            .filter(otherProperty -> otherProperty.getUsed())            .map(OtherProperty::getId)            .collect(Collectors.toList());    //在传递回来的配件二级分类其他属性中校对没有修改过的,没有使用过的其他属性,只对修改过的,没有使用过的其他属性进行    //存储,否则不处理    List changeList = otherProperties.stream().filter(otherProperty -> Optional.ofNullable(otherProperty.getId()).isPresent())            .filter(otherProperty -> !unUsedList.contains(otherProperty))            .filter(otherProperty -> !usedIdList.contains(otherProperty.getId()))            .peek(otherProperty -> otherPropertyDao.deleteOtherPropertiesById(otherProperty.getId()))            .collect(Collectors.toList());    if (changeList.size() > 0) {        StringBuilder builder = new StringBuilder();        changeList.stream().map(OtherProperty::getId).forEach(eachId -> builder.append(eachId + ","));        String newIds = builder.toString().substring(0, builder.toString().length() - 1);        ((ProviderProductLevel) level2).deletePropertyIdfromLevel(newIds);        ((ProviderProductLevel) level2).addOtherProperties(changeList);    }//获取新增的其他属性进行追加到配件二级分类的其他属性中    List newList = otherProperties.stream().filter(otherProperty -> !Optional.ofNullable(otherProperty.getId()).isPresent())            .peek(otherProperty -> otherProperty.setId(idService.genId()))            .collect(Collectors.toList());    ((ProviderProductLevel) level2).addOtherProperties(newList);    return Result.success("修改成功");}

在进行一番增删改查后,数据库中的数据大致如下

我们查高级项链的所有属性的结果如下

现在我们要在属于该商品分类中添加商品,商品类定义大致如下

@Data@NoArgsConstructorpublic class ProviderProduct implements Provider {    private Product product; //配件元信息对象    private String code; //配件编码    private Brand brand; //品牌    private String details; //配件图文说明    private String levelName; //二级配件分类名称    private DefaultProvider provider; //配件商    private ExtBeanWrapper otherValues; //其他属性集合}

其中对应于属性列表的字段为otherValues,这个值正是我们要存入数据库的Json字段类型映射。

商品的数据库表结构如下

要使用mybatis的数据对Json字段类型的转换,可以先引用一个网上写好的转换器,当然也可以自己写

pom

   com.github.jeffreyning   extcol   0.0.1-RELEASE

配置文件中添加 type-handlers-package: com.nh.micro.ext.th

mybatis:  type-aliases-package: com.cloud.model.productprovider  type-handlers-package: com.nh.micro.ext.th  mapper-locations: classpath:/mybatis-mappers/*  configuration:    mapUnderscoreToCamelCase: true

在mapper文件中写入一段插入语句

    insert into product (id,name,code,model,normal_price,price_begin,product_imgs,details,brand_id,other_property_value)    values (#{product.id},#{product.name},#{code},#{product.model},#{product.price.normalPrice},                    1                    0    ,    #{product.productImgs},    #{details},    #{brand.id},    #{otherValues,jdbcType=VARCHAR}    )

对应商品分类的每一个自定义属性,我们可以先拿到该自定义属性的id,然后以该id,取值为键值对进行插入

{
"product":{
"name":"AAAA",
"model":"AAAAA",
"price":{
"normalPrice":199,
"begin":false
},
"productImgs":"http://123.433.567.988"
},
"code":"0001",
"details":"",
"brand":{
"id":1,
"name":"飞利浦"
},
"otherValues":{
"innerMap":{
"2459623566996408120":"10",
"2459623566996409144":"呼和浩特",
"2459623566996410168":"飞利浦",
"2459623566996411192":"国际",
"2459623566996412216":"包邮"
}
}
}

执行之后,数据库的数据如下

该插件的数据类和转换器的源码如下,其实也是很简单的

public class ExtBeanWrapper {   public ExtBeanWrapper() {   };   public ExtBeanWrapper(Object entity) {      this.setObj(entity);   }   private Map innerMap = new HashMap();   public Map getInnerMap() {      return innerMap;   }   public void setInnerMap(Map innerMap) {      this.innerMap = innerMap;   }   public void setObj(Object entity) {      if (entity == null) {         innerMap = null;      }      JSON jobj = (JSON) JSON.toJSON(entity);      innerMap = JSON.toJavaObject(jobj, Map.class);   }   public Object getObj() {      if (innerMap == null) {         return null;      }      JSON jobj = (JSON) JSON.toJSON(innerMap);      Map entity = JSON.toJavaObject(jobj, Map.class);      return entity;   }   public Object getObj(Class targetClass) {      if (innerMap == null) {         return null;      }      JSON jobj = (JSON) JSON.toJSON(innerMap);      Object entity = JSON.toJavaObject(jobj, targetClass);      return entity;   }}
MappedTypes(com.nh.micro.ext.ExtBeanWrapper.class)@MappedJdbcTypes(JdbcType.VARCHAR)public class TagToJsonTypeHandler extends BaseTypeHandler {   private Map jsonToMap(String value) {      if (value == null || "".equals(value)) {         return Collections.emptyMap();      } else {         return JSON.parseObject(value, new TypeReference>() {         });      }   }   @Override   public void setNonNullParameter(PreparedStatement ps, int i, ExtBeanWrapper parameter, JdbcType jdbcType)         throws SQLException {         ps.setString(i, JSON.toJSONString(parameter.getInnerMap()));   }   public boolean isJson(String value){      if(value==null || "".equals(value)){         return false;      }else{         if(value.startsWith("{")){return true;         }      }      return false;   }   @Override   public ExtBeanWrapper getNullableResult(ResultSet rs, String columnName) throws SQLException {      String value=rs.getString(columnName);      Map innerMap=jsonToMap(value);      ExtBeanWrapper extBeanTag=new ExtBeanWrapper();      extBeanTag.setInnerMap(innerMap);      return extBeanTag;   }   @Override   public ExtBeanWrapper getNullableResult(ResultSet rs, int columnIndex) throws SQLException {      String value=rs.getString(columnIndex);      Map innerMap=jsonToMap(value);      ExtBeanWrapper extBeanTag=new ExtBeanWrapper();      extBeanTag.setInnerMap(innerMap);      return extBeanTag;   }   @Override   public ExtBeanWrapper getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {      String value=cs.getString(columnIndex);      Map innerMap=jsonToMap(value);      ExtBeanWrapper extBeanTag=new ExtBeanWrapper();      extBeanTag.setInnerMap(innerMap);      return extBeanTag;   }}

现在我们来看一下如何将该Json字段从数据库取出,还是以上面的案例为例,先在mapper文件中定义一组resultMap

                                                                                                                                

这里稍微解释一下,price里的begin是boolean类型,price_begin在数据库中是整形,有一个转换器,代码如下

public class BoolIntTypeHandler extends BaseTypeHandler {@Override    public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException {        ps.setBoolean(i,parameter);    }@Override    public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {int value = rs.getInt(columnName);        if (rs.wasNull()) {return false;        }else {if (value == 0) {return false;            }else if (value == 1) {return true;            }        }return false;    }@Override    public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {int value = rs.getInt(columnIndex);        if (rs.wasNull()) {return false;        }else {if (value == 0) {return false;            }else if (value == 1) {return true;            }        }return false;    }@Override    public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {int value = cs.getInt(columnIndex);        if (cs.wasNull()) {return false;        }else {if (value == 0) {return false;            }else if (value == 1) {return true;            }        }return false;    }}

品牌这里有一个查找

配件二级分类名称

配件商信息

                            

当然我们的重点还是otherValues这里

    

获取数据的全部select代码如下

获取出来的数据如下

{     "code": 200,     "data": {         "brand": {             "code": "001",             "id": 1,             "logoUrl": "http://123.456.789",             "name": "飞利浦",             "sort": 1         },         "code": "0001",         "levelName": "高级项链",         "otherValues": {             "innerMap": {                 "2459623566996411192": "国际",                 "2459623566996408120": "10",                 "2459623566996409144": "呼和浩特",                 "2459623566996410168": "飞利浦",                 "2459623566996412216": "包邮"             },             "obj": {                 "2459623566996410168": "飞利浦",                 "2459623566996411192": "国际",                 "2459623566996408120": "10",                 "2459623566996409144": "呼和浩特",                 "2459623566996412216": "包邮"             }         },         "product": {             "id": 2459722970793247544,             "model": "AAAAA",             "name": "AAAA",             "onShelf": false,             "price": {                 "begin": false,                 "normalPrice": 199             }         },         "provider": {             "code": "0001",             "productProvider": {                 "id": 2459698718186668856,                 "name": "大众4S店",                 "productList": []             },             "status": false         }     },     "msg": "操作成功" }

当然我们这里要把其他属性的id替换成用户能看懂的其他属性的名称

@Overridepublic Provider findProduct(Long id) {    ProductDao productDao = SpringBootUtil.getBean(ProductDao.class);    OtherPropertyDao otherPropertyDao = SpringBootUtil.getBean(OtherPropertyDao.class);    Provider product = productDao.findProductById(id);    Map map = ((ProviderProduct) product).getOtherValues().getInnerMap();    Map insteadMap = new HashMap<>();    for (Object key : map.keySet()) {log.info("键名为:" + String.valueOf(key));        String name = otherPropertyDao.findNameById(Long.parseLong(String.valueOf(key)));        insteadMap.put(name,(String) map.get(key));    }    ((ProviderProduct) product).getOtherValues().setObj(insteadMap);    return product;}

最后我们获取的结果为

{     "code": 200,     "data": {         "brand": {             "code": "001",             "id": 1,             "logoUrl": "http://123.456.789",             "name": "飞利浦",             "sort": 1         },         "code": "0001",         "levelName": "高级项链",         "otherValues": {             "innerMap": {                 "商品等级": "国际",                 "运费设置": "包邮",                 "生产厂家": "飞利浦",                 "包装规格": "10",                 "商品产地": "呼和浩特"             },             "obj": {                 "$ref": "$.data.otherValues.innerMap"             }         },         "product": {             "id": 2459722970793247544,             "model": "AAAAA",             "name": "AAAA",             "onShelf": false,             "price": {                 "begin": false,                 "normalPrice": 199             }         },         "provider": {             "code": "0001",             "productProvider": {                 "id": 2459698718186668856,                 "name": "大众4S店",                 "productList": []             },             "status": false         }     },     "msg": "操作成功" }

以上是"Mybatis中怎么样操作mysql8的Json字段类型"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

属性 配件 商品 分类 字段 数据 类型 飞利 飞利浦 数据库 名称 国际 呼和浩特 高级 成功 代码 对象 文件 转换器 项链 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 失去了数据库安装教程 小班网络安全教育教案有那些 数据库建设基本流程图doc下载 上网共建网络安全倡议书 网络安全作文400字 民政学院软件开发住宿环境 python建一个数据库 数据库领域把表又称为 网络安全讲课举例 网络安全精品课程网站建设 软件开发南找78 867 淮北点餐系统软件开发 中国电信2022年服务器集采 安卓vpn服务器地址免费 深圳纳海网络技术有限公司 2021网络安全和信息化 雪崩互联网科技怎么样 玩的游戏的服务器忘记了怎么办 成都银行软件开发中心年薪多少 临沂瑞创网络技术有限公司 网络安全重保期间是什么意思 sql数据库手机版软件 辽宁智慧景区软件开发公司 网络安全优秀作文900字 数据库统计周期字段用啥类型 阿里云里怎么看服务器地址 服务器托管机房 中国电信 网上订餐软件开发费用 软件开发可研报告 临沂瑞创网络技术有限公司
0