千家信息网

Mybatis深度整合Mysql的Json字段

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,概述以前当业务数据结构变化时,往往需要采用的方案是:修改表结构增加字段遇到数据结构有list结构时,新建1对多的关联子表用字典表表示字段的增加以上方案对代码侵入性很强,同时与旧业务数据结构不兼容
千家信息网最后更新 2024年11月11日Mybatis深度整合Mysql的Json字段

概述
以前当业务数据结构变化时,往往需要采用的方案是:
修改表结构增加字段
遇到数据结构有list结构时,新建1对多的关联子表
用字典表表示字段的增加
以上方案对代码侵入性很强,同时与旧业务数据结构不兼容。导致代码从实体类
、Dao、Service、Controller层都要修改。

随着NOSQL数据库的广泛应用,可扩展的存储方式在关系型数据库中也有了很好的支持,最新的MySQL5.7中就新增加了一个数据类型JSON,使用mysql的json类型字段做扩展字段,可以以json串形式动态的存储任意结构的数据,包括list结构的数据也不必再创建子表。代码的实体类和Dao层不必修改,其他层代码修改量也能够减少。

Mysql常见json字段操作
Mysql5.7开始支持json字段
创建带有json字段的表micro_test,其中extcol为json类型字段

CREATE TABLE `micro_test` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `meta_name` varchar(100) DEFAULT NULL COMMENT '元数据名称',  `create_time` datetime DEFAULT NULL COMMENT '创建时间',  `update_time` datetime DEFAULT NULL COMMENT '更新时间',  `extcol` json DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB CHARSET=utf8;

插入json字段
可按照json字符串插入json字段

Insert into micro_test (extcol,meta_name,create_time) values('{"name":"tomcat","age":15}','123',now());

查询json字段
可以根据path查询json字段中全部或部分数据
Select meta_name,extcol->>'$.name' as name,extcol->>'$.age' as age from micro_test;

修改json字段
可以根据path局部更新json字段中数据
Update micro_test set extcol=json_set(extcol,'$.name','jeffrey') where meta_name='123'

Mysql5.7.22版本以后支持JSON_MERGE_PATCH
可以省略path参数,全面更新json字段中数据

Update micro_test set extcol=json_set(extcol,'{"name":"n1","age":30}') where meta_name='123'

Mybatis使用Json字段
按照mybatis常规方式把json函数写入到xml文件中的sql中,即可支持json字段增删改查。但查询出的json字段为字符串类型,需要手工转成bean,插入时需手工把bean转成json字符串,这样做不利于面向对象编程。

Mybatis深度整合Json字段
实现bean与json串在mybatis内部转换,这样做的优点是dao层代码和sql不变,service层可以增删改查不同的动态Entity对象。更符合面向对象编程习惯提高开发效率。

Extcol开源项目实现Mybatis与mysql的json字段深度整合
项目地址为:
https://github.com/jeffreyning/extcol.git

pom引用extcol的jar

    com.github.jeffreyning    extcol    0.0.1-RELEASE

Extcol包中TypeHandler子类TagToJsonTypeHandler 实现mybatis在数据库操作过程中的参数输入和结果转换的拦截。拦截父类为ExtBeanWrapper的对象。
使TagToJsonTypeHandler生效需要配置

mybatis-plus:  typeHandlersPackage: com.nh.micro.ext.th

Extcol包中ExtBeanWrapper类,作为json对象转换的目标对象,内有map成员变量保存实际数据,getobj和setobj方法是使用fastjson做对象与map的转换。

使用Extcol的Demo
引入和配置好extcol后,在demo业务系统工程中编写对应micro_test表的实体类TestDto,其中json字段的成员变量类型是ExtBeanWrapper。

public class TestDto  {    private Integer id;    private String metaKey;    private String metaName;    private String metaType;    private Date createTime;    private ExtBeanWrapper extcol;    public ExtBeanWrapper getExtcol() {        return extcol;    }    public void setExtcol(ExtBeanWrapper extcol) {    }

扩展字段业务bean
例如扩展bean为ExtEntity有两个在数据库中json字段动态存储的字段t1和t2

public class ExtEntity {    private String t1;    private String t2;    public String getT1() {        return t1;    }    public void setT1(String t1) {        this.t1 = t1;    }    public String getT2() {        return t2;    }    public void setT2(String t2) {        this.t2 = t2;    }}

在以TestDto为更新和插入时的参数操作时,mybatis将负责将bean转为json串

        insert into micro_test(meta_name,extcol,create_time) values (#{metaName},#{extcol},now()) 

当执行查询语句时,返回的结果映射到ExtBeanWrapper 类型的字段时,mybatis将负责将json串转为ExtBeanWrapper ,且这个ExtBeanWrapper 可以按照不同的业务bean自适应转化。

                        

取查询结果中JSON字段中存储的业务类ExtEntity 的代码

    public List testQuery4JsonXml(String name){        List retList=testDao.getInfo4JsonXml(name);        if(retList!=null){            for(TestDto testDto:retList){                ExtBeanWrapper extBeanWrapper=testDto.getExtcol();                ExtEntity extEntity=(ExtEntity) extBeanWrapper.getObj(ExtEntity.class);                System.out.println(extEntity.getT1());            }        }        return retList;    }

Mybatisplus的bean更新时使用JSON_MERGE_PATCH
修改mybatisplus的AutoSqlInjector

    private String getPlaceTag(String row){        int start=row.indexOf("#{");        int end=row.indexOf("}")+1;        String temp=row.substring(start,end);        System.out.println(temp);        return temp;    }    private String getColTag(String row){        int end=row.indexOf("=#{");        int start=0;        if(row.contains("")+1;        }        String temp=row.substring(start,end);        System.out.println(temp);        return temp;    }    private String createNewPlace(String colTag,String placeTag){        String temp="json_merge_patch("+colTag+","+placeTag+")";        return temp;    }    protected void injectUpdateByIdSql(boolean selective, Class mapperClass, Class modelClass, TableInfo table) {        SqlMethod sqlMethod = selective ? SqlMethod.UPDATE_BY_ID : SqlMethod.UPDATE_ALL_COLUMN_BY_ID;        String temp=sqlSet(selective, table, "et.");        String osql=temp;        if(selective){            String[] tempArray=temp.split("\n\t");            StringBuilder sb=new StringBuilder("");            for(String row:tempArray){                if(row.contains("typeHandler")){                    System.out.println(getPlaceTag(row));                    String placeTag=getPlaceTag(row);                    System.out.println(getColTag(row));                    String colTag=getColTag(row);                    String nPlaceTag=createNewPlace(colTag, placeTag);                    System.out.println(nPlaceTag);                    row=row.replace(placeTag, nPlaceTag);                    sb.append(row).append("\n\t");                }else{                    sb.append(row).append("\n\t");                }            }            osql=sb.toString();        }        String sql = String.format(sqlMethod.getSql(), table.getTableName(), osql, table.getKeyColumn(),                "et." + table.getKeyProperty(),                ""                        + ""                        + "and ${et.MP_OPTLOCK_VERSION_COLUMN}=#{et.MP_OPTLOCK_VERSION_ORIGINAL}"                        + ""                        + ""        );        System.out.println(sql);        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);        this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);    }
字段 数据 对象 结构 业务 代码 类型 更新 查询 数据库 存储 支持 动态 参数 字符 字符串 实体 数据结构 结果 深度 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全个人信息存储 sql数据库连接端口 网络安全工作责任制试点 苏州c语言软件开发服务 新吴区微型软件开发注意事项 药智数据库中的kol信息在哪里 贵州网络安全防线 窃入式软件开发 深圳微商软件开发常见问题 融汇网络技术 苏州专业软件开发工程师 恩度网络技术有限公司 奇迹后台在哪里清理数据库 滨州市网络安全知识答题 广安网络安全等级 svn服务器端管理 网购中网络安全存在哪些问题 普陀区管理软件开发包括什么 学生网络安全知识总结小点 违反网络安全法第46条 期权软件开发平台哪个好 SRA数据库中有siRNA吗 对会计软件开发企业的建议 对计算机网络安全的期望 联想服务器管理接口无法访问 金山区公司软件开发售后服务 数据库备份设置账户信息 北京博越广维网络技术 如何查数据库增长的数据 大学生网络安全知识竞赛好难
0