使用 myBatis 从 DB 中读取 JSON

Posted

技术标签:

【中文标题】使用 myBatis 从 DB 中读取 JSON【英文标题】:Reading a JSON from DB with myBatis 【发布时间】:2019-02-23 02:10:48 【问题描述】:

我在 DB 中有一个列,我想将其保存为 JSON 并将其取回。

我的做法是:

我将其保存为ClobTypeHandler,并尝试将其检索为ClobTypeHandler

我正在使用Mybatis,但是出现以下错误。

Could not set property 'idType' of 'class package.abc' with value '"idNum":"123","text":"ENCkk-KZJTmN8Mr5jEims0rssRow8xaAnkOtl0RQHDth1ByVtshI7zQebtcogOvYM-gNo15DwwPmduaufk03CteqRL03cRyrG4%3B","key":"P]H73AFTGB$OIDCYVIIB+VW4TR)I?U_`_ZXP[UY$BJNXVU~/@!F%+SVMFYT/2IAXIOPB"' Cause: java.lang.IllegalArgumentException: argument type mismatch

下面是java层和DB细节。

class abc

    private JsonNode idType;

    public String getIdType() 
         return idType != null ? idType.toString():null;
    
    public void setIdType(JsonNode idType) 
        this.idType = idType;
    

mapper.xml(插入数据库)

INSERT INTO CUSTOMER
    (<include refid="common_customer_insert_columns"></include>,id_type)        
 VALUES
    (<include refid="common_customer_insert_fields"></include>,<include refid="cc_customer_insert_fields"></include>,
        <choose> <when test="abc.idType !=null">#abc.idType,typeHandler= org.apache.ibatis.type.ClobTypeHandler</when>
                <otherwise>''</otherwise></choose>);

mapper.xml(从 DB 读取时)

<resultMap>
    <result column="id_type" property="abc.idType" 
        typeHandler="org.apache.ibatis.type.ClobTypeHandler" />
</resultMap>

我正在尝试保存和检索的示例 JSON 值:

"idType":   
       "idNum": "123",  
       "text": "ENh-KZJTmN8Mr5jEims0rssRow8xaADth1ByVtshI7zQebtcogOvYM-gNo15DwwPmduaufk03CteqRLaVwF0b3cRyrG4%3D",  
       "key":"P]H73AFTGB$OICQ*DCYVIIB+VW4TR)I?U_`_ZXP[UY$BJNXV@!F%+SVMFYT/2IAXIOPB"  
        

【问题讨论】:

对此的任何更新,面临同样的问题 【参考方案1】:

您可以在不使用 POJO 的情况下做到这一点:

ObjectMapper mapper = new ObjectMapper();
JsonNode idType = mapper.readTree(<json-string>);

【讨论】:

是的,但我需要 POJO,因为 POJO 包含与此字段一起的其他字段【参考方案2】:

ClobTypeHandler 扩展了BaseTypeHandler&lt;String&gt;,因此它允许将数据库列中的值设置和检索为String。当您像这样使用ClobTypeHandler 时:

#abc.idType,typeHandler= org.apache.ibatis.type.ClobTypeHandler

mybatis 在底层期望abc.getIdType 返回String,它确实如此。到目前为止一切顺利。

当您从数据库中检索值时,使用的映射是:

<result column="id_type" property="abc.idType"
     typeHandler="org.apache.ibatis.type.ClobTypeHandler" />

在这种情况下,ClobTypeHandler 尝试使用setIdType 设置器设置idType 属性,并希望它接受String。但是 setter 参数是 JsonNode,因此您会收到类型不兼容的消息。

要修复此更改,类型设置器获取并在其中进行从 StringJsonNode 的转换:

public void setIdType(String idTypeString) 
     ObjectMapper mapper = new ObjectMapper();
     this.idType = mapper.readTree(isTypeString);

注意:你 can use 静态 ObjectMapper 以避免在每次调用时创建它。

更好的方法是为类型JsonNode 创建your own TypeHandler。它会在内部进行String JsonNode 转换,因此您的abc 不会被这个(不相关的)逻辑所污染。

【讨论】:

使用 objectMapper 修改我的 setter 方法后出现以下错误:- package.abc["idType"])" error="com.fasterxml.jackson.databind.JsonMappingException - 无法反序列化实例START_OBJECT 令牌中的 java.lang.String 【参考方案3】:

要将数据(Pojo 类)保存为 JSON 值并读取为 POJO 类,我们需要编写自定义 TypeHandler

假设我们有一个 Employee 类,其中配置对象需要在数据库中保存为 JSON 并读取为配置对象

Employee.java

public class Employee 
    private int id;
    private String name;
    private Config config; //save as josn in DB

Config.java

public class Config implements Serializable
        private static final long serialVersionUID = 1L;
        private String key;
        private String value;
        private String msg;
        private int referenceNumber;

JsonTypeHandler.java

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


@MappedTypes(Config.class)
public class JsonTypeHandler extends BaseTypeHandler<Config>  

    ObjectMapper objectMapper = new ObjectMapper();

    
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Config config, JdbcType jdbcType) throws SQLException 
        try 
            preparedStatement.setObject(i, objectMapper.writeValueAsString(config));

         catch (JsonProcessingException e) 
            e.printStackTrace();
        
    

    @Override
    public Config getNullableResult(ResultSet resultSet, String s) throws SQLException 
        if(resultSet.getString(s) != null)
            try 
                return objectMapper.readValue(resultSet.getString(s), Config.class);
             catch (JsonProcessingException e) 
                e.printStackTrace();
            
        
        return null;
    

    @Override
    public Config getNullableResult(ResultSet resultSet, int i) throws SQLException 
        if(resultSet.getString(i) != null)
            try 
                return objectMapper.readValue(resultSet.getString(i), Config.class);
             catch (JsonProcessingException e) 
                e.printStackTrace();
            
        
        return null;
    

    @Override
    public Config getNullableResult(CallableStatement callableStatement, int i) throws SQLException 
        if(callableStatement.getString(i) != null)
            try 
                return objectMapper.readValue(callableStatement.getString(i), Config.class);
             catch (JsonProcessingException e) 
                e.printStackTrace();
            
        
        return null;
    

MyBatis 插入查询

@Insert("insert into employee(name, config) values(#employee.name, #employee.config, typeHandler=com.example.demo.image.JsonTypeHandler)")
    void saveEmployee(@Param("employee") Employee employee);

MyBatis 选择查询

@Results(
            @Result(property = "id", column = "id"),
            @Result(property = "name", column = "name"),
            @Result(property = "config", column = "config", typeHandler =com.example.demo.image.JsonTypeHandler.class),

    )
    @Select("select id, name, config from employee")
        List<Employee> getAll();

【讨论】:

以上是关于使用 myBatis 从 DB 中读取 JSON的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis为啥会从数据库读取出NULL来

springboot整合mybatis,redis,代码

springboot整合mybatis,redis,代码

Octave:从 sqlite db 文件中读取 BLOB 数据

从 H2DB 读取结果

读取大量记录 (Batch READ) DB2