错误:列是 json 类型,但表达式在 Hibernate 中是不同的字符类型

Posted

技术标签:

【中文标题】错误:列是 json 类型,但表达式在 Hibernate 中是不同的字符类型【英文标题】:ERROR: column is of type json but expression is of type character varying in Hibernate 【发布时间】:2021-04-05 06:26:33 【问题描述】:

我需要使用spring data jpa在postgres中将实体类的两列映射为json。在阅读了多个***帖子和baeldung帖子后,

How to map a map JSON column to Java Object with JPA

https://www.baeldung.com/hibernate-persist-json-object

我做了如下配置。但是,我面临错误“错误:列“标题”是 json 类型,但表达式的类型是字符变化

请提供一些指针来解决此问题。

我有一个实体类如下

@Entity
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class Task 
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;
    
    private String url;
    private String httpMethod;

    @Convert(converter = HashMapConverter.class)
    @Column(columnDefinition = "json")
    private Map<String, String> headers;

    @Convert(converter = HashMapConverter.class)
    @Column(columnDefinition = "json")
    private Map<String, String> urlVariables;

我创建了一个测试类来测试实体是否被持久化。在运行这个 junit 时,下面的测试用例失败,错误如下

@SpringBootTest
class TaskRepositoryTest 

    private static Task randomTask = randomTask();

    @Autowired
    private TaskRepository taskRepository;

    @BeforeEach
    void setUp() 
        taskRepository.deleteAll();
        taskRepository.save(randomTask);
    

    public static Task randomTask() 
        return randomTaskBuilder().build();
    

    public static TaskBuilder randomTaskBuilder() 
        Map<String,String> headers = new HashMap<>();
        headers.put(randomAlphanumericString(10),randomAlphanumericString(10));

        Map<String,String> urlVariables = new HashMap<>();
        urlVariables.put(randomAlphanumericString(10),randomAlphanumericString(10));

        return builder()
                .id(randomPositiveInteger())
                .httpMethod(randomAlphanumericString(10))
                .headers(headers)
                .urlVariables(urlVariables)
                .url(randomAlphanumericString(10)));
    

使用 liquibase,我在 postgres DB 中创建了表,我可以看到列数据类型为 json。

databaseChangeLog:
  - changeSet:
      id: 1
      author: abc
      changes:
        - createTable:
            tableName: task
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: url
                  type: varchar(250)
                  constraints:
                    nullable: false
                    unique: true
              - column:
                  name: http_method
                  type: varchar(50)
                  constraints:
                    nullable: false
              - column:
                  name: headers
                  type: json
              - column:
                  name: url_variables
                  type: json
      rollback:
        - dropTable:
            tableName: task

【问题讨论】:

这看起来像一个字符串,而不是 json:headers.put(randomAlphanumericString(10),randomAlphanumericString(10)); @Frank Heikens 是的,这是地图,但 HashMapConverter.class 应在写入 DB 之前将实体属性转换为 json。 在你提到的教程中使用Map&lt;String, Object&gt;,而你使用Map&lt;String, String&gt; @NikolaiShevchenko 因为我的要求是 Map 而不是 Map @user2800089 那么你应该调整HashMapConverter来处理Map&lt;String,String&gt; 【参考方案1】:

以上配置无效。

因此,我按照下面的链接来解决用例

https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/

"Provider com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule not found" after Spring Boot Upgrade

在 pom.xml 中添加了额外的依赖项

        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vladmihalcea</groupId>
            <artifactId>hibernate-types-52</artifactId>
            <version>2.9.11</version>
        </dependency>

移除 HashMapConverter 配置并在实体类中进行以下更改

@Entity
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@TypeDefs(
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
)
public class Task 
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;
    
    private String url;
    private String httpMethod;

    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Map<String, String> headers;

    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Map<String, String> urlVariables;

经过这些更改,TaskRepositoryTest 通过了。

【讨论】:

【参考方案2】:

我在将项目从 mysql 8.0.21 迁移到 Postgres 13 时遇到了这个问题。我的项目使用带有 Hibernate 类型依赖项版本 2.7.1 的 Spring Boot。就我而言,解决方案很简单。

我需要做的就是改变它并且它起作用了。

引用自Hibernate Types Documentation page。

【讨论】:

【参考方案3】:

对于因使用JdbcTemplate 并收到此错误而登陆此处的任何人,解决方案非常简单:在您的 SQL 语句中,使用 ::jsonb 强制转换 JSON 参数。

例如String INSERT_SQL = "INSERT INTO xxx (id, json_column) VALUES(?, ?)"; 变成String INSERT_SQL = "INSERT INTO xxx (id, json_column) VALUES(?, ?::jsonb)";

【讨论】:

感谢@spork,它正在工作 也为我工作

以上是关于错误:列是 json 类型,但表达式在 Hibernate 中是不同的字符类型的主要内容,如果未能解决你的问题,请参考以下文章

hiber

当列是 JSON 数组而不是字符串时如何过滤 ANTD 表

当列是整数和小数的混合时,创建表时使用哪种数据类型?

运行第二天出现hibernate的错误,org.hibernate.TransactionException: JDBC commit failed at org.hiber

使用键名索引 json 对象给出错误 [[keyname]] 不能用于索引类型“对象”

Date类型错误