带有 Postgres 的 JPA 在@Lob 列中异常地将文本写入为数字

问题描述

我正在尝试使用具有 Java @Lob 类型的 String 列将其内容映射到 Postgres 中的 TEXT。这是相关实体:

@Entity(name="Metadata")
public class Metadata {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "created_on")
    @ColumnDefault(value="CURRENT_TIMESTAMP")
    @Generated(GenerationTime.INSERT)
    private LocalDateTime createdOn;

    @Lob
    @Column(name = "content")
    private String content;

    @Column(name = "draft")
    private Boolean draft;

    @OnetoMany(cascade = javax.persistence.CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "Metadata")
    private List<Attachment> attachments;

    public void addAttachment(Attachment attachment) {
        if (attachments == null) {
            attachments = new ArrayList<>();
        }
        attachments.add(attachment);
        attachment.setMetadata(this);
    }

    // getters and setters
}

我有基于使用输入创建新 Metadata 实体的​​代码。我在 IntelliJ 调试模式下手动验证该实体将 content 设置为其预期值(恰好是 JSON 字符串)。然而,当我在运行代码后检查 Postgres 时,我看到了这个数据:

my_db=> select * from Metadata;
 id | content |       created_on        | draft
----+---------+-------------------------+-------
  1 | 49289   | 2021-04-26 14:21:25.733 | t
(1 row)

请注意,奇怪的值 49289 出现在我们希望看到 JSON 字符串的位置。请注意,我还从命令行验证了正确的表是创建的:

CREATE TABLE scarfon_attachment (
    id bigint NOT NULL,contents text,filename character varying(255),scarfon_id bigint NOT NULL
);

实体/表中的所有其他列都按预期工作。 @Lob 注释可能有什么问题。作为参考,我正在运行一个相当旧版本的 Postgres (9.2),但它并不是那么古老。

解决方法

当使用 @Lob 时,Hibernate ORM 会期望数据库中有一个 text 类型的列,您可以使用它来保存最大为 1 Gb 的文本文件。

您可以避免使用它,它会将列的类型更改为 VARCHAR(255)。 不同之处在于您可以限制 VARCHAR 的大小,ORM 的默认值为 255,但您不能限制 text 的大小。

您还可以更改默认列类型(我认为 varchar 可以大到 1Gb):

@Column(name = "content",columnDefinition = "varchar(500)")
String content

因此,最终使用哪种方法取决于您。我假设对于大字符串 text 更好,但您需要评估您的用例。

,

我在这里的第一个疑问是由于许多来源提出了创建 TEXT 列的多种方法。例如,this Baeldung post 建议除了使用带有 @Lob 注释的定义外还使用 @Column

事实证明,并非所有数据库都对 @Lob 进行了相同的解释。在 Postgres 的情况下,仅使用 @Lob 将导致 Postgres 将列内容存储在不同 表中,使用 @Lob 注释的列仅存储每个的 ID该表中的条目。虽然有人建议 here 通过 @Type 注释指定正确的类型也可以解决这个问题,但我决定采用 Baledung 帖子的第二个建议,它使用 @Column :

@Lob
@Column(columnDefinition="TEXT")
private String content;

这工作正常,并且生成的 Postgres 表具有预期的 TEXT 定义。上述唯一的潜在问题可能集中在对其他 SQL 数据库的可移植性,这些数据库可能不支持 TEXT 类型,或者可能支持某些替代方案。我没有在 Postgres 和 H2 之外进行测试,但在这两种情况下,上述方法都没有问题。