MyBaties存储和查询json格式的数据(实体存储查询版本)

最近在做的功能,由于别的数据库有值,需要这边的不同入口的进来查询,所以需要同步过来,如果再继续一个一个生成列对应处理感觉不方便,如果没有别的操作,只是存储和查询,那就可以用MySql支持的json格式存储了。

MySql的json是5.7之后才可以处理的,所以版本一定要是这个或者比这个高呦!

首先第一步我们需要定义个处理json类型类,可以叫BaseAttributeTypeHandler,来继承BaseTypeHandler这个ibatis的类,一定要定义类型,后期传参用,

java 复制代码
package xx;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.lettuce.core.dynamic.support.ResolvableType;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.util.Assert;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author df
 * @Description: 基础类, 处理mySql字段为json类型
 * @Date 2023/10/19 9:52
 */
public abstract class BaseAttributeTypeHandler<T> extends BaseTypeHandler<Object> {

    private JavaType javaType;

    /**
     * ObjectMapper
     */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 构造方法
     */
    public BaseAttributeTypeHandler() {
        // 通过class构造一个ResolvableType对象
        ResolvableType resolvableType = ResolvableType.forClass(getClass());
        // 获取对应泛型实体
        Type type = resolvableType.as(BaseAttributeTypeHandler.class).getGeneric() != null ?
                resolvableType.as(BaseAttributeTypeHandler.class).getGeneric().getType() :
                null;
        // 根据对应类型构造出java类型
        javaType = constructType(type);
    }

    private static JavaType constructType(Type type) {
        Assert.notNull(type, "[Assertion failed] - type is required; it must not be null");
        return TypeFactory.defaultInstance().constructType(type);
    }


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, JSONUtil.toJsonStr(parameter));
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return convertToEntityAttribute(value);
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convertToEntityAttribute(rs.getString(columnIndex));
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return convertToEntityAttribute(value);
    }

    private Object convertToEntityAttribute(String dbData) {
        // 根据得到的数据判断类型
        if (StrUtil.isEmpty(dbData)) {
            if (List.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyList();
            } else if (Set.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptySet();
            } else if (Map.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyMap();
            } else {
                return null;
            }
        }
        return toObject(dbData, javaType);
    }

    private static <T> T toObject(String json, JavaType javaType) {
        Assert.hasText(json, "[Assertion failed] - this json must have text; it must not be null, empty, or blank");
        Assert.notNull(javaType, "[Assertion failed] - javaType is required; it must not be null");
        try {
            // 给对象设置值
            return (T) OBJECT_MAPPER.readValue(json, javaType);
        } catch (com.fasterxml.jackson.core.JsonParseException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

定义要存储的json类型的实体类,假如存储个用户信息把,我们就定义了UserSportTypeHandler,然后继承刚才的类BaseAttributeTypeHandler,传入json实体UserSport(你们自己定义的要存储或者查询出来的实体哈)

java 复制代码
public class UserSportTypeHandler extends BaseAttributeTypeHandler<UserSport> {
}

存储时在po实体里添加如下的说明,好让MySql知道是json,这里的typeHandler则定义为UserSportTypeHandler

java 复制代码
   
@Data
public class User {
    
    private Long id;
    
    private String username;

    @TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class)
    private UserSport userSport;

}

新增

调用mybatis插件直接保存即可

java 复制代码
public class UserBusinessImpl extends ServiceImpl<UserMapper, User> implements UserBusiness {

    public Boolean saveSportDataBatch(List<User> users) {
         super.saveBatch(users);
    }

}

测试下,可以哦,直接存储了json的数据

当然还可以存储list以及list<json>这样的格式,可以这样改。

java 复制代码
public class UserSportTypeHandler extends BaseAttributeTypeHandler<List<UserSport>> {
}

也可以在mapper.xml里这样添加,也要指明typeHadler

XML 复制代码
 <insert id="saveBatch" parameterType="java.util.List">
        INSERT INTO user_sport_record (user_sport)
        <foreach collection="list" separator="," item="item">
            VALUES (
                    #{item.userSport,javaType=com.uniigym.Uniiuser.infrastructure.po.HeartDistribute,typeHandler=HeartDistributeTypeHandler,jdbcType=OTHER});
        </foreach>
    </insert>

查询

当然你要是自己在mapper里写,可以在resultMap下里写,示例:

XML 复制代码
<resultMap type="xx.po.User" id="user">
        <result property="id" column="id" jdbcType="INTEGER"/>
      
        <!-- json需要配置如下才能查询出来数据 -->
        <result typeHandler="com.uniigym.Uniiuser.common.config.mybatis.HeartDistributeTypeHandler"
                property="heartDistribute" column="heart_distribute"
                jdbcType="OTHER" javaType="com.uniigym.Uniiuser.infrastructure.po.HeartDistribute"/>
    </resultMap>

这样查询和添加都可以用这个,但是要在sql种指定resultMap的id,但是如果实体上写了 @TableField(jdbcType = JdbcType.OTHER, typeHandler = UserSportTypeHandler.class),就不用在ResultMap标签在定义了。如果都不配置typeHandler则关于json的字段查询出来为空,只有对了查询和保存才可以处理。

相关推荐
亚林瓜子17 小时前
Jackson注解屏蔽某些字段读取权限
spring·json·jackson
不惑_1 天前
最佳实践 · 如何高效索引MySQL JSON字段
java·mysql·json
天上掉下来个程小白2 天前
请求响应-05.请求-日期参数&JSON参数
spring boot·json
敲代码不忘补水2 天前
Python Pickle 与 JSON 序列化详解:存储、反序列化与对比
开发语言·python·json
jackletter2 天前
c#:System.Text.Json 的使用四(如何忽略[JsonPropertyName])
c#·json·序列化
A 八方2 天前
Python JSON
开发语言·python·json
小故渊3 天前
JSON对象
运维·服务器·json
SelectDB技术团队3 天前
查询性能提升 10 倍、存储空间节省 65%,Apache Doris 半结构化数据分析方案及典型场景
数据结构·数据仓库·elasticsearch·log4j·json
D11_4 天前
pandas:读取各类文件方法以及爬虫时json数据保存
爬虫·python·数据分析·json·pandas
深夜吞食4 天前
项目实现:云备份③(配置文件加载模块、数据管理模块的实现)
linux·c语言·c++·json