使用 Spring / JPA 写入 Postgres 数据库的 JSON 列

Writing to JSON column of Postgres database using Spring / JPA

我有一个名为 "test" 的 table,其中包含 Postgres 9.3 中类型为 json 的列 "sample_column"。我正在尝试使用 Spring / JPA 将以下内容写入列中:{"name":"Updated name"}

我在其他帖子上读到我需要添加一个自定义转换器来将字符串映射到 json 类型。这是我现在的代码:

TestDAO.java:

@Entity
@Table(name="test")
public class TestDAO implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id", unique=true, nullable=false)
    private Long id;   

    @Column(name="sample_column")
    @Convert(converter = MyCustomConverter.class)
    private MyCustomClass sampleColumn;

    // Getter / Setters
}

用于映射 json 内容的 CustomClass:

public class MyCustomClass {
    @JsonProperty("name")
    public String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

最后,ConverterClass:

@javax.persistence.Converter
public class MyCustomConverter implements AttributeConverter<MyCustomClass, String> {

    private final static ObjectMapper objectMapper = new ObjectMapper();

    @Override
    @NotNull
    public String convertToDatabaseColumn(@NotNull MyCustomClass myCustomObject) {
        try {
            return objectMapper.writeValueAsString(myCustomObject);
        } catch (Exception ex) {
            return null;
        }
    }

    @Override
    @NotNull
    public MyCustomClass convertToEntityAttribute(@NotNull String databaseDataAsJSONString) {
        try {
            return objectMapper.readValue(databaseDataAsJSONString, MyCustomClass.class);
        } catch (Exception ex) {
            return null;
        }
    }
}

现在,我尝试按如下方式设置 json 列:

testDAO.getSampleColumn().setName("Updated name");
testRepository.saveAndFlush(testDAO);

但是当我尝试保存它时,出现以下错误:

Caused by: org.postgresql.util.PSQLException: ERROR: column "sample_column" is of type json but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.

但是,我可以使用 testDAO.getSampleColumn().getName(); 阅读 JSON 列 这里有什么问题?我不想向 table 添加任何转换以自动将 Varying 转换为 Json。

谢谢。

您需要在 JDBC 级别使用 setObject,或者传递 PgJDBC 参数 stringtype=unspecified 以允许从字符串类型隐式转换为 json

这是 PostgreSQL 对类型转换过于严格的问题。

对于使用 Spring-boot 的人来说,有两种方法可以做到@Craig Ringer 所说的

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified

或使用属性

spring.datasource.hikari.data-source-properties.stringtype=unspecified

虽然两者都有效,但我建议使用 PGobject 功能,而不是在连接级别设置该功能。

final ObjectMapper objectMapper = new ObjectMapper();
PGobject languageObject = new PGobject();
languageObject.setType("json");
languageObject.setValue(objectMapper.writeValueAsString(blogPosts.getLanguages()));

完成后,将参数传递给 Spring jdbctemplate 来完成魔法

希望如此。

您需要将 JSON 转换为字符串,然后从中创建一个 PGobject。这个解决方案对我有用:

PGobject pGobject = new PGobject();
pGobject.setType("json");
pGobject.setValue(vehicleJsonData);

    try {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(connection -> {
            PreparedStatement ps = connection.prepareStatement(SQL_CREATE, Statement.NO_GENERATED_KEYS);
            ps.setLong(1, id);
            ps.setObject(2, pGobject);
            return ps;
        }, keyHolder);

    } catch (Exception e) {
        e.printStackTrace();
    }