1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        extcolMybatis深度整合Mysql的Json字段

        聯(lián)合創(chuàng)作 · 2023-09-30 01:46

        概述

        以前當(dāng)業(yè)務(wù)數(shù)據(jù)結(jié)構(gòu)變化時(shí),往往需要采用的方案是:

        1. 修改表結(jié)構(gòu)增加字段
        2. 遇到數(shù)據(jù)結(jié)構(gòu)有l(wèi)ist結(jié)構(gòu)時(shí),新建1對(duì)多的關(guān)聯(lián)子表
        3. 用字典表表示字段的增加

        以上方案對(duì)代碼侵入性很強(qiáng),同時(shí)與舊業(yè)務(wù)數(shù)據(jù)結(jié)構(gòu)不兼容。導(dǎo)致代碼從實(shí)體類(lèi)

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

         

        隨著NOSQL數(shù)據(jù)庫(kù)的廣泛應(yīng)用,可擴(kuò)展的存儲(chǔ)方式在關(guān)系型數(shù)據(jù)庫(kù)中也有了很好的支持,最新的MySQL5.7中就新增加了一個(gè)數(shù)據(jù)類(lèi)型JSON,使用mysql的json類(lèi)型字段做擴(kuò)展字段,可以以json串形式動(dòng)態(tài)的存儲(chǔ)任意結(jié)構(gòu)的數(shù)據(jù),包括list結(jié)構(gòu)的數(shù)據(jù)也不必再創(chuàng)建子表。代碼的實(shí)體類(lèi)和Dao層不必修改,其他層代碼修改量也能夠減少。

         

        Mysql常見(jiàn)json字段操作

        Mysql5.7開(kāi)始支持json字段

        創(chuàng)建帶有json字段的表micro_test,其中extcol為json類(lèi)型字段

        CREATE TABLE `micro_test` (

          `id` int(11) NOT NULL AUTO_INCREMENT,

          `meta_name` varchar(100) DEFAULT NULL COMMENT '元數(shù)據(jù)名稱(chēng)',

          `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',

          `update_time` datetime DEFAULT NULL COMMENT '更新時(shí)間',

          `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());

         

        查詢(xún)json字段

        可以根據(jù)path查詢(xún)json字段中全部或部分?jǐn)?shù)據(jù)

        Select meta_name,extcol->>'$.name' as name,extcol->>'$.age' as age from micro_test;

         

        修改json字段

        可以根據(jù)path局部更新json字段中數(shù)據(jù)

        Update micro_test set extcol=json_set(extcol,'$.name','jeffrey') where meta_name='123'

         

        Mysql5.7.22版本以后支持JSON_MERGE_PATCH

        可以省略path參數(shù),全面更新json字段中數(shù)據(jù)

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

         

        Mybatis使用Json字段

        按照mybatis常規(guī)方式把json函數(shù)寫(xiě)入到xml文件中的sql中,即可支持json字段增刪改查。但查詢(xún)出的json字段為字符串類(lèi)型,需要手工轉(zhuǎn)成bean,插入時(shí)需手工把bean轉(zhuǎn)成json字符串,這樣做不利于面向?qū)ο缶幊獭?/p>

        Mybatis深度整合Json字段

        實(shí)現(xiàn)bean與json串在mybatis內(nèi)部轉(zhuǎn)換,這樣做的優(yōu)點(diǎn)是dao層代碼和sql不變,service層可以增刪改查不同的動(dòng)態(tài)Entity對(duì)象。更符合面向?qū)ο缶幊塘?xí)慣提高開(kāi)發(fā)效率。

         

         

        Extcol開(kāi)源項(xiàng)目實(shí)現(xiàn)Mybatis與mysql的json字段深度整合

        項(xiàng)目地址為:

        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子類(lèi)TagToJsonTypeHandler 實(shí)現(xiàn)mybatis在數(shù)據(jù)庫(kù)操作過(guò)程中的參數(shù)輸入和結(jié)果轉(zhuǎn)換的攔截。攔截父類(lèi)為ExtBeanWrapper的對(duì)象。

        使TagToJsonTypeHandler生效需要配置

        mybatis-plus:

          typeHandlersPackage: com.nh.micro.ext.th

         

         

        Extcol包中ExtBeanWrapper類(lèi),作為json對(duì)象轉(zhuǎn)換的目標(biāo)對(duì)象,內(nèi)有map成員變量保存實(shí)際數(shù)據(jù),getobj和setobj方法是使用fastjson做對(duì)象與map的轉(zhuǎn)換。

         

        使用Extcol的Demo

        引入和配置好extcol后,在demo業(yè)務(wù)系統(tǒng)工程中編寫(xiě)對(duì)應(yīng)micro_test表的實(shí)體類(lèi)TestDto,其中json字段的成員變量類(lèi)型是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) {

        }

         

        擴(kuò)展字段業(yè)務(wù)bean

        例如擴(kuò)展bean為ExtEntity有兩個(gè)在數(shù)據(jù)庫(kù)中json字段動(dòng)態(tài)存儲(chǔ)的字段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為更新和插入時(shí)的參數(shù)操作時(shí),mybatis將負(fù)責(zé)將bean轉(zhuǎn)為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>

         

         

         

         

        當(dāng)執(zhí)行查詢(xún)語(yǔ)句時(shí),返回的結(jié)果映射到ExtBeanWrapper 類(lèi)型的字段時(shí),mybatis將負(fù)責(zé)將json串轉(zhuǎn)為ExtBeanWrapper ,且這個(gè)ExtBeanWrapper 可以按照不同的業(yè)務(wù)bean自適應(yīng)轉(zhuǎn)化。

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

         

        取查詢(xún)結(jié)果中JSON字段中存儲(chǔ)的業(yè)務(wù)類(lèi)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更新時(shí)使用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);

            }

         

         

         

        瀏覽 26
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        編輯 分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        編輯 分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            上面吃奶下面日 | 亚洲欧美成人在线 | 欧美性生活视频 | AV2014天堂网 | 中文字幕大香区 | 小舞被唐三扒开腿狂动漫 | 国产成人无码免费视频 | 99国产伦清品一区二区三区 | 好涨嗯太深了嗯啊用力停 | 久久精品夜夜夜夜夜久久 |