使用 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<String>
,因此它允许将数据库列中的值设置和检索为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
,因此您会收到类型不兼容的消息。
要修复此更改,类型设置器获取并在其中进行从 String
到 JsonNode
的转换:
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的主要内容,如果未能解决你的问题,请参考以下文章