mysql Json Column使用

mysql json列

springboot-mysql-json项目地址
##使用场景
我们在创建表的时候总是习惯多预留出来几列,以防以后出现需求增加或者变更的时候,如果添加表的列,在数据量非常大的情况下锁表,但是如果添加关联表的话,查询的时候,又会拖慢速度,在当今服务的大部分性能障碍都是被数据库拖累,所以mysq在5.7.1之后新加了json属性。下面我们看看这个怎么用。
##创建表和数据
###创建表
一个简单的sql,你愿意创建在哪里都行,只要你的程序以后能链接的上就行。

-- auto-generated definition
create table lnmp
(
  id        bigint unsigned auto_increment
    primary key,
  category  json null,
  tags      json null
);

创建表的两个列category和tags设置为json格式,可以为null,之后我们创建一个springboot的demo项目,然后添加100000的数据,

添加数据

我们就用最简单的jdbc来创建数据,代码如下

package com.example.demo;

import com.example.demo.entity.UserInfo;
import com.google.gson.Gson;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Test
    public void contextLoads() {
    }


    @Test
    public void InsertDB() throws ClassNotFoundException, SQLException {
        final String url = "jdbc:mysql://localhost:3306/zgg_customer?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai";
        final String driverClassName = "com.mysql.jdbc.Driver";
        final String username = "root";
        final String password = "123456";
        Connection conn = null;
        Class.forName(driverClassName);//指定连接类型
        conn = DriverManager.getConnection(url, username, password);//获取连接

        Gson gson = new Gson();
        //sql前缀
        String prefix = "insert into lnmp (category, tags) values  ";
        //开始写后缀
        Random random = new Random();
        //设置事务非自动提交
        conn.setAutoCommit(false);
        Statement st = conn.createStatement();
        for (int i = 0; i <100 ; i++) {
            StringBuffer suffix = new StringBuffer();
            //第一次提交步长
            for (int j = 0; j <1000 ; j++) {
                UserInfo userInfo = new UserInfo(i, "name" + i, "https://www" + i + ".baidu.com");
                suffix.append("('"+gson.toJson(userInfo)+"','"+ gson.toJson(Collections.singleton(i))+"') ");
                //完整sql语句
                String sql = prefix + suffix;
                st.executeUpdate(sql);
                conn.commit();
                suffix = new StringBuffer();
            }

        }
        st.close();
        conn.close();
    }
}

项目结构

如下是我的项目结构,具体的代码我就不粘贴出来了,呆一会咱们就讲mapper文件里的sql怎么写就行。
在这里插入图片描述
##数据操作
###添加数据
添加数据和我们日常添加数据没有什么区别,在对应的java程序,他就是String,所以我们看看mapper文件的添加sql和对象
在这里插入图片描述
左边是数据库要映射到的对象。右边是category要做的json数据。
java程序(我写死了)

        Lnmp lnmp = new Lnmp();
        Gson gson = new Gson();
        lnmp.setCategory(gson.toJson(new UserInfo(1000001, "张三", "https://blog.csdn.net/lovemenghaibin/article/details/90031424")));
        lnmp.setTags(gson.toJson(Arrays.asList(1, 2, 3, 5)));
        int count = lnmpMapper.save(lnmp);
        return count;
        

xml文件

    <insert id="save">
        insert into lnmp (category, tags) values (#{category}, #{tags})
    </insert>

添加很简单,就不在赘述了
###查询
####根据条件查询
例如我要根据category中的json的name条件查询,那么我们就可以如下操作:

SELECT *
FROM lnmp
where category -> '$.name' = 'name3';

查询结果如下
在这里插入图片描述
在mapper中:

<select id="selectAllInfo" resultMap="BaseResultMap">
        SELECT *
        FROM lnmp
        where category -> '$.name' = #{name } limit 200;
    </select>
    

可以写成

<select id="selectAllInfo" resultMap="BaseResultMap">
SELECT *
FROM lnmp
where json_extract(category, '$.name') = #{name};
    </select>
    

如果是精确匹配,我还是推荐写成第一种,和lambda很像,以后的精确匹配的写法我也是直接用第一种,当然这里也可以进行模糊查询,模糊查询的时候就需要用到里边的函数。相面我门专门来讲一下这里的函数。

模糊查询

因为保存的json里是"name2",“name21”,所以查询的条件是"name2.

select *
from lnmp where json_extract(category, '$.name') like concat('"', '"name2', '%') ;

我们发现这里有一个问题就是如果查询的是字符串,在前边还需要加",这是因为咱们object->json的时候就有了这个信息,当然我们保存起来没有问题,为了区分是字符串还是数字,但是在查询时候,尤其是模糊查询,我们还是不想拼双引号然后查询的,这个时候就用json_unquote方法把json_extract方法被包住就可以了,

扫描二维码关注公众号,回复: 8641492 查看本文章
select *
from lnmp where json_unquote(json_extract(category, '$.name'))  like concat('', 'name2', '%') ;

当然上边的两种写法都可以用我上边说的方法来表示,分别是

select *
from lnmp where category -> '$.name' like concat('', '"name2', '%') ;

select *
from lnmp where category ->> '$.name' like concat('', 'name2', '%') ;

查询某一行的字段有哪些key

select id, json_keys(category)
from lnmp where id = 1002;

查询结果如下
1002 ["id", "url", "name"]
####其他命令

  • json_array 创建json数组
  • json_object 创建json对象
  • json_quote 将json转成json字符串类型查json
  • json_contains 判断是否包含某个json值
  • json_contains_path 判断某个路径下是否json值
  • json_extract 提取json值
  • column->path json_extract的简洁写法,MySQL 5.7.9开始支持
  • column->>path json_unquote(column -> path)的简洁写法
  • json_keys 提取json中的键值为json数组
  • json_search 按给定字符串关键字搜索json,返回匹配的路径修改json
  • json_append 废弃,MySQL 5.7.9开始改名为json_array_append
  • json_array_append 末尾添加数组元素,如果原有值是数值或json对 象,则转成数组后,再添加元素
  • json_array_insert 插入数组元素
  • json_insert 插入值(插入新值,但不替换已经存在的旧值)
  • json_merge 合并json数组或对象
  • json_remove 删除json数据
  • json_replace 替换值(只替换已经存在的旧值)
  • json_set 设置值(替换旧值,并插入不存在的新值)
  • json_unquote 去除json字符串的引号,将值转成string类型返回json属性
  • json_depth 返回json文档的最大深度
  • json_length 返回json文档的长度
  • json_type 返回json值得类型
  • json_valid 判断是否为合法json文档

##添加索引
但是随着我们的数据量变大了以后,我们希望在json中也加入索引,方法如下,例如要给category中的name添加索引,采用如下方式添加索引,然后我们在执行下边的查询与语句。

alter table lnmp add column user_name varchar(20) generated always as (category ->>'$.name') (virtual|stored) ;
explain select *
from lnmp where category ->> '$.name'  = 'name2';

在这里插入图片描述
我们可以看到是精确匹配了的,当然我们还是希望这个最好不要设计到复杂的业务。
上边我们说的创建索引,其实是基于mysql的Generated Column,简单来说,就是我们要先创建一个列,然后给这个列创建索引,这个创建的列可以是虚拟的,也可以是实际存储在磁盘上的,对应的就是Virtual Generated Column和Stored Generated Column,Virtual Generated Column还有很多限制:能作为主键、不能创建全文索引和空间索引等,但是普通索引还是可以用的。Stored是可以作为多种索引
所以具体用那种,就看需求了。

发布了176 篇原创文章 · 获赞 84 · 访问量 44万+

猜你喜欢

转载自blog.csdn.net/lovemenghaibin/article/details/101215463
今日推荐