You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JPA和Hibernate 6向Spanner插入JSON数据报错求助

问题:使用JPA+Hibernate 6向Spanner JSON列插入数据时类型不匹配

插入数据时触发如下错误:

Error:
Value has type STRING which cannot be inserted into column json_data, which has type JSON

已参考相关Spanner JPA集成资料但未解决问题,附上代码及配置详情,求解决建议:


实体类

import com.google.cloud.spanner.hibernate.PooledBitReversedSequenceStyleGenerator;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.type.SqlTypes;

import java.util.Map;

@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "demo")
public class Demo {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
    @GenericGenerator(
            name = "sequence_generator",
            strategy = "com.google.cloud.spanner.hibernate.PooledBitReversedSequenceStyleGenerator",
            parameters = {
                    @org.hibernate.annotations.Parameter(name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "demo_sequence"),
                    @org.hibernate.annotations.Parameter(name = SequenceStyleGenerator.INCREMENT_PARAM, value = "200"),
                    @org.hibernate.annotations.Parameter(name = SequenceStyleGenerator.INITIAL_PARAM, value = "50000"),
                    @org.hibernate.annotations.Parameter(name = PooledBitReversedSequenceStyleGenerator.EXCLUDE_RANGE_PARAM, value = "[1,1000]"),
            })
    private Long id;

    @JdbcTypeCode(SqlTypes.JSON)
    private Map<String, Object> jsonData;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Map<String, Object> getJsonData() {
        return jsonData;
    }

    public void setJsonData(Map<String, Object> jsonData) {
        this.jsonData = jsonData;
    }
}

DDL和DML语句

drop table IF EXISTS demo;
drop sequence IF EXISTS demo_sequence;
CREATE SEQUENCE demo_sequence OPTIONS (
  sequence_kind="bit_reversed_positive"
);
create table demo(
    id INT64 NOT NULL default (GET_NEXT_SEQUENCE_VALUE(SEQUENCE demo_sequence)),
    json_data JSON,
) PRIMARY key(id);

insert into demo(json_data) values (JSON '{"name":"tom","age":30}');

POM依赖配置

<properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-spanner-hibernate-dialect</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-spanner</artifactId>
            <version>6.80.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>spring-cloud-gcp-data-spanner</artifactId>
            <version>5.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
            <version>3.3.5</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-spanner-jdbc</artifactId>
            <version>2.24.1</version>
        </dependency>
        <dependency>
            <groupId>com.vladmihalcea</groupId>
            <artifactId>hibernate-types-60</artifactId>
            <version>2.21.1</version>
        </dependency>
    </dependencies>

解决建议

1. 增强JSON字段的类型注解

仅使用@JdbcTypeCode(SqlTypes.JSON)可能无法被Spanner方言正确识别,结合hibernate-types的@Type注解明确指定JSON类型处理器:

import com.vladmihalcea.hibernate.type.json.JsonType;
// ...
@Type(JsonType.class)
@JdbcTypeCode(SqlTypes.JSON)
private Map<String, Object> jsonData;

2. 对齐依赖版本兼容性

google-cloud-spanner-hibernate-dialect与google-cloud-spanner-jdbc版本需匹配,当前方言版本3.3.0建议搭配对应版本的JDBC驱动,避免版本不兼容导致的类型转换错误。

3. 配置Hibernate全局JSON类型映射

在application.properties中添加以下配置,强制Hibernate使用Spanner兼容的JSON类型处理逻辑:

spring.jpa.properties.hibernate.type.preferred_json_jdbc_type=JSON
spring.jpa.properties.hibernate.dialect=com.google.cloud.spanner.hibernate.SpannerDialect

4. 移除冲突依赖

当前依赖中同时引入了spring-cloud-gcp-data-spanner和JPA相关依赖,二者可能存在类型处理逻辑冲突。如果使用JPA+Hibernate方案,建议移除spring-cloud-gcp-data-spanner依赖。

5. 验证SQL生成逻辑

开启Hibernate SQL日志,查看插入语句的参数绑定情况:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

若日志显示插入的是字符串而非JSON字面量,说明类型转换未生效,需进一步调整注解或配置。


内容的提问来源于stack exchange,提问作者Suga Raj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:54:54