知識庫 / JPA RSS 訂閱

解決 JPA 中 PostgreSQL JSON 類型不匹配錯誤

JPA,JSON
HongKong
8
09:43 PM · Dec 05 ,2025

1. 引言

在本教程中,我們將探討常見 <em>PSQLException</em> 錯誤:“列的數據類型為 json,但表達式的數據類型為 character varying” 當使用 JPA 與 PostgreSQL 交互時。 我們將探討該錯誤發生的原因,識別觸發該錯誤的一些常見場景,並演示如何解決它。

2. 常見原因

在 PostgreSQL 中,<em >JSON</em><em >JSONB</em> 數據類型用於存儲 JSON 數據。然而,如果嘗試將字符串(character varying)插入到期望存儲 JSON 的列中,PostgreSQL 會拋出“<em >列的數據類型為 json,但表達式的數據類型為 character varying</em>” 錯誤。這在與 JPA 和 PostgreSQL 一起工作時尤其常見,因為 JPA 可能會嘗試將字符串保存到 JSON 列中,從而導致此錯誤。

3. 演示錯誤

我們將創建一個包含必要的依賴項和測試數據,用於演示錯誤的簡單 Spring Boot 項目。首先,我們需要將 PostgreSQL 依賴項添加到我們的 Maven pom.xml 文件中:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.1</version>
    <scope>runtime</scope>
</dependency>

接下來,我們創建一個 JPA 實體類,將其映射到 student 表:

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

    private String admitYear;

    @Column(columnDefinition = "json")
    private String address;

    // getters and setters
}

在實體類中,address 字段映射到 student 表中的 address 列。 值得注意的是,我們指定了 columnDefinition 屬性為 JSON,以指示該列的類型為 JSON

現在,讓我們嘗試將一個 Student 對象保存到數據庫中:

Student student = new Student();
student.setAdmitYear("2024");
student.setAddress("{\"postCode\": \"TW9 2SF\", \"city\": \"London\"}");

Throwable throwable = assertThrows(Exception.class, () -> studentRepository.save(student));
assertTrue(ExceptionUtils.getRootCause(throwable) instanceof PSQLException);

在這段代碼中,我們創建了一個 Student 對象並將 address 字段設置為 JSON 字符串。 然後,我們使用 studentRepository 對象中的 save() 方法將此對象保存到數據庫。

然而,這導致 PSQLException

Caused by: org.postgresql.util.PSQLException: ERROR: column "address" is of type json but expression is of type character varying

此錯誤發生的原因是,JPA 嘗試將字符串保存到 JSON 列中,這被禁止。

4. 使用 @Type 註解

為了解決此問題,我們需要正確處理 JSON 類型。 我們可以使用 @Type 註解,該註解由 hibernate-types 庫提供。 首先,讓我們將 hibernate-types 依賴添加到我們的 pom.xml 中:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.18.0</version>
</dependency>

接下來,我們更新實體,使其包含 @TypeDef@Type 註解:

@Entity
@Table(name = "student_json")
@TypeDefs({
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class StudentWithTypeAnnotation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String admitYear;

    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private String address;

    // Getters and Setters
}

這裏,,它使用了來自 hibernate-types-52 庫的 處理 PostgreSQL 的 的形式高效地存儲和檢索。

, 我們告訴 Hibernate 使用通過 。 這個自定義類型處理 Java 對象與 PostgreSQL 中 數據類型高效地存儲和檢索:

StudentWithTypeAnnotation student = new StudentWithJson();
student.setAdmitYear("2024");
student.setAddress("{\"postCode\": \"TW9 2SF\", \"city\": \"London\"}");
studentWithTypeAnnotationRepository.save(student);

StudentWithTypeAnnotation retrievedStudent = studentWithTypeAnnotationRepository.findById(student.getId()).orElse(null);

assertThat(retrievedStudent).isNotNull();
assertThat(retrievedStudent.getAddress()).isEqualTo("{\"postCode\":\"TW9 2SF\",\"city\":\"London\"}");

5. 本地查詢

此外,當我們使用帶有本地 SQL 查詢的 @Query 註解將 JSON 數據插入到 PostgreSQL 表中時,也會遇到相同的錯誤。 讓我們通過創建一個本地查詢來演示這個錯誤:

@Query(value = "INSERT INTO student (admit_year, address) VALUES (:admitYear, :address) RETURNING *", nativeQuery = true)
Student insertJsonData(@Param("admitYear") String admitYear, @Param("address") String address);

當我們用 JSON 字符串調用此方法時,我們期望會收到異常。

Throwable throwable = assertThrows(Exception.class, () -> 
  studentRepository.insertJsonData("2024","{\"postCode\": \"TW9 2SF\", \"city\": \"London\"}"));
assertTrue(ExceptionUtils.getRootCause(throwable) instanceof PSQLException);

要解決這個問題,我們需要在插入之前將 JSON 字符串轉換為 JSONB 類型,以避免出現此錯誤。

以下是一個示例,説明如何執行此操作:

public interface StudentWithTypeAnnotationRepository extends JpaRepository<StudentWithTypeAnnotation, Long> {
    @Query(value = "INSERT INTO student (admit_year, address) VALUES (:admitYear, CAST(:address AS JSONB)) RETURNING *", nativeQuery = true)
    StudentWithTypeAnnotation insertJsonData(@Param("admitYear") String admitYear, @Param("address") String address);
}

在上述代碼中,我們使用 <em>CAST(:address AS JSONB)</em> 語法將 <em>:address</em> 參數轉換為 <em>JSONB</em> 類型。現在,讓我們測試此方法:

StudentWithTypeAnnotation student = studentWithJsonRepository.insertJsonData("2024","{\"postCode\": \"TW9 2SF\", \"city\": \"London\"}");

StudentWithTypeAnnotation retrievedStudent = studentWithJsonRepository.findById(student.getId()).orElse(null);

assertThat(retrievedStudent).isNotNull();
assertThat(retrievedStudent.getAddress()).isEqualTo("{\"city\": \"London\", \"postCode\": \"TW9 2SF\"}");

6. 結論

在本文中,我們探討了如何解決 PSQLException 錯誤“列的數據類型為 json,但表達式為 character varying” 的問題,該問題在通過 JPA 將 Java 對象映射到 PostgreSQL JSON 列時出現。

通過使用 @Type 註解並使用原生 SQL 查詢時將 JSON 字符串轉換為 JSONB 類型,我們可以高效地在 PostgreSQL 中存儲和檢索 JSON 數據,利用 JSONB 數據類型。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.