Mybatis深度整合Mysql的Json字段

栏目: 数据库 · 发布时间: 6年前

内容简介:概述以前当业务数据结构变化时,往往需要采用的方案是:修改表结构增加字段

概述

以前当业务数据结构变化时,往往需要采用的方案是:

修改表结构增加字段

遇到数据结构有list结构时,新建1对多的关联子表

用字典表表示字段的增加

以上方案对代码侵入性很强,同时与旧业务数据结构不兼容。导致代码从实体类

、Dao、Service、Controller层都要修改。

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

Mybatis深度整合Mysql的Json字段

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深度整合Mysql的Json字段

Mybatis深度整合Json字段

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

Mybatis深度整合Mysql的Json字段

Extcol开源项目实现Mybatis与mysql的json字段深度整合

项目地址为:

https://github.com/jeffreyning/extcol.git

pom引用extcol的jar

<dependency>
    <groupId>com.github.jeffreyning</groupId>
    <artifactId>extcol</artifactId>
    <version>0.0.1-RELEASE</version>
</dependency>

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串

<update id="insertInfo4JsonXml" parameterType="com.test.nm.order.dto.TestDto">
        insert into micro_test(meta_name,extcol,create_time) values (#{metaName},#{extcol},now()) 
</update>

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

<resultMap id="TestDto" type="com.test.nm.order.dto.TestDto" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="meta_name" property="metaName" jdbcType="VARCHAR" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="extcol" property="extcol" jdbcType="VARCHAR" />
  </resultMap>

    <select id="getInfo4JsonXml" resultMap="TestDto" parameterType="java.lang.String">
        SELECT * from micro_test where meta_name=#{name}
    </select>

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

public List<TestDto> testQuery4JsonXml(String name){
        List<TestDto> 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("<if")){
            start=row.indexOf(">")+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(),
                "<if test=\"et instanceof java.util.Map\">"
                        + "<if test=\"et.MP_OPTLOCK_VERSION_ORIGINAL!=null\">"
                        + "and ${et.MP_OPTLOCK_VERSION_COLUMN}=#{et.MP_OPTLOCK_VERSION_ORIGINAL}"
                        + "</if>"
                        + "</if>"
        );
        System.out.println(sql);

        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);
    }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Coming of Age in Second Life

Coming of Age in Second Life

Tom Boellstorff / Princeton University Press / 2008-04-21 / USD 29.95

The gap between the virtual and the physical, and its effect on the ideas of personhood and relationships, is the most interesting aspect of Boellstorff's analysis... Boellstorff's portrayal of a virt......一起来看看 《Coming of Age in Second Life》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试