Spring Java JPA 将 String 保存为 tinyblob,导致 json 解析错误

Posted

技术标签:

【中文标题】Spring Java JPA 将 String 保存为 tinyblob,导致 json 解析错误【英文标题】:Spring Java JPA is saving String as tinyblob, giving json parse error 【发布时间】:2021-09-28 19:09:05 【问题描述】:

我有两个实体,具有一对一的关系。我希望一个做父母,另一个做孩子:

父级:MappingPayload,代码如下:

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "duplicate_handling_id", referencedColumnName = "id")
private DuplicateHandling duplicateHandling;

孩子:使用以下代码进行重复处理:

    public MappingPayload() 
    this.id = null;

private String dupAction;
    @OneToOne(mappedBy = "duplicateHandling")
    private MappingPayload mappingPayload;

问题在于 DuplicateHandling 类中的私有字符串 dupAction。它作为 tinyblob 保存在 mysql 中,应该是 varchar。 (注意其他类中还有其他String字段被正确保存为varchar)

问题仅在于 DuplicateHandling 类,所以如果我添加更多字符串字段,它们也会保存为 tinyblob。我也尝试过手动更改数据库中的数据类型。

当我发送以下 json 时:

 
"mappingPayload":
    "duplicateHandling": "dupAction":"we are"

我收到以下错误:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.sun.org.apache.xpath.internal.operations.String` 

(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('we are'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.sun.org.apache.xpath.internal.operations.String` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('we are')
 at [Source: (PushbackInputStream); line: 3, column: 37] (through reference chain: com.amos.amosintegrationprocessor.requests.CreateMappingRequest["mappingPayload"]->com.amos.amosintegrationprocessor.entities.MappingPayload["duplicateHandling"]->com.amos.amosintegrationprocessor.entities.DuplicateHandling["dupAction"])]

这是来自 gradle 文件的版本信息:'org.springframework.boot' version '2.5.2'

【问题讨论】:

【参考方案1】:

一个对象必须作为一个实体来引用。如果不这样做,jpa 会将其视为二进制,并将序列化的二进制放入数据库列中。

解决方案 1) 使其成为一个实体

简单地将其设为实体意味着使用 @Entity & Column 映射对其进行注释,从而生成一个新表

解决方案 2) 使其可嵌入

使用@Embeddable 注解代替@OneToOne 将使类的属性嵌套到父级的表表示中。

@Entity
public class MappingPayload 
   
   @Embedded
   private DuplicateHandling duplicateHandling;

@Embeddable
public class DuplicateHandling 
   private String json;

这将导致 JPA 将 DuplicateHandling 中的列嵌套到 MappingPayload 中。这不是问题,因为它以前是 1:1 的关系。

永远记住,如果你将 DuplicateHandling 这样的复杂类型存储到数据库中而不告诉 JPA 如何存储它,它就会变成一个 blob。

可嵌入的技巧将使您的字符串保持不变。

一般提示:

如果您有结构化数据和关系数据库,请不要将 json 序列化为列,除非它们是真正需要的。如果您只有一个普通的类,则将其设置为新实体并引用它会更加通用。而且更干净。

【讨论】:

感谢您的评论。请注意,重复处理是一个实体,目前我已删除所有其他字段,但它将包含更多数据。不幸的是,所有字符串属性都给出了 json 解析错误并保存为 tinyblob。我认为我没有理解您的解决方案,如果您能详细说明,我将不胜感激。其次,第二个解决方案不起作用,Intelij 想让我删除它。我将 @Embaddable 放在父 MappingPayload 字段中的 privae DuplicateHandling duplicateHangling 对象之上。 请看示例 另外,您可能想检查一下baeldung.com/jpa-embedded-embeddable

以上是关于Spring Java JPA 将 String 保存为 tinyblob,导致 json 解析错误的主要内容,如果未能解决你的问题,请参考以下文章

表单提交错误,无法将类型“java.lang.String”的值转换为浏览器中所需的类型错误,在 Spring MVC 中

JPA 将 java.io.File 或 java.nio.file.Path 对象映射到 STRING 列

使用 Spring Boot 和 JPA 将存储过程输出到 Java 自定义对象中

JAVA spring (JPA) 中的PostgreSQL + Elasticsearch 同步

Spring+Jpa插入boolean属性出现异常问题

带有 JPA 的 Spring Boot:将 @Entity 移动到不同的包