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

JPA with Postgres anomalously writes text in @Lob column as a number

我正在尝试使用具有 Java String 类型的 @Lob 列将其内容映射到 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 字符串的位置。请注意,我还从命令行验证了正确的 table 是创建的内容:

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

entity/table 中的所有其他列都按预期工作。 @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 将列内容存储在 不同的 table 中,该列用 [=12= 注释] 只是为 table 中的每个条目存储一个 ID。虽然有人建议 here 通过 @Type 注释指定正确的类型也可以解决这个问题,但我决定采用 Baledung post 的第二个建议,它使用 @Column:

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

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