错误:关系 xxx 的“id”列中的空值违反非空约束 - Spring Data JPA

Posted

技术标签:

【中文标题】错误:关系 xxx 的“id”列中的空值违反非空约束 - Spring Data JPA【英文标题】:ERROR: null value in column "id" of relation xxx violates not-null constraint - Spring Data JPA 【发布时间】:2022-01-11 21:21:38 【问题描述】:

我对 Spring JPA 中的 @GeneratedValue 注释有疑问。

这是我的课:

@Entity
@NoArgsConstructor
@Getter
@Setter
public class Product 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private Double price;
    private Integer quantity;

    @ManyToOne
    private Category category;

    @ManyToOne
    private Manufacturer manufacturer;



    public Product(String name, Double price, Integer quantity, Category category, Manufacturer manufacturer) 
        this.name = name;
        this.price = price;
        this.quantity = quantity;
        this.category = category;
        this.manufacturer = manufacturer;
    

当我尝试添加新产品时出现此错误:

2021-12-06 18:03:02.013 ERROR 3720 --- [nio-9090-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: null value in column "id" of relation "product" violates not-null constraint
  Detail: Failing row contains (null, Dress, 333, 33, 1, 1).
2021-12-06 18:03:02.028 ERROR 3720 --- [nio-9090-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [id" of relation "product]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

org.postgresql.util.PSQLException: ERROR: null value in column "id" of relation "product" violates not-null constraint
  Detail: Failing row contains (null, Dress, 333, 33, 1, 1).

这是我的服务类中的保存方法:

@Override
    public Optional<Product> save(String name, Double price, Integer quantity, Long categoryId, Long manufacturerId) 
        Category category = this.categoryRepository.findById(categoryId).orElseThrow(() -> new CategoryNotFoundException(categoryId));
        Manufacturer manufacturer = this.manufacturerRepository.findById(manufacturerId).orElseThrow(() -> new ManufacturerNotFoundException(manufacturerId));

        this.productRepository.deleteByName(name);

        return Optional.of(this.productRepository.save(new Product(name, price, quantity, category, manufacturer)));
    

老实说,我不知道这是怎么发生的。我在某处读到 PostgreSQL 不支持 GenerationType.IDENTITY,但我不认为是这样,因为我对 CategoryManufacturer 表使用了相同的生成类型,我可以向它们添加新元组没有问题。我尝试使用生成类型 SEQUENCE 并且 它可以工作,但我不想使用该生成类型并且我不明白为什么 IDENTITY 不会在这里工作在其他 who 表上工作。有什么想法吗?

编辑 1: 使用 GenerationType.AUTO 对其进行了测试,它可以工作,但对于 IDENTITY 类型仍然显示相同的错误。

编辑 2: 共享用于创建 Product 表和 Category 表的 SQL。

CREATE TABLE IF NOT EXISTS public.product
(
    id bigint NOT NULL,
    name character varying(255) COLLATE pg_catalog."default",
    price double precision,
    quantity integer,
    category_id bigint,
    manufacturer_id bigint,
    CONSTRAINT product_pkey PRIMARY KEY (id),
    CONSTRAINT fk1mtsbur82frn64de7balymq9s FOREIGN KEY (category_id)
        REFERENCES public.category (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT fkq5vxx1bolpwm1sngn6krtwsjn FOREIGN KEY (manufacturer_id)
        REFERENCES public.manufacturers (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

TABLESPACE pg_default;

ALTER TABLE public.product
    OWNER to wp;
CREATE TABLE IF NOT EXISTS public.category
(
    id bigint NOT NULL DEFAULT nextval('category_id_seq'::regclass),
    description character varying(4000) COLLATE pg_catalog."default",
    name character varying(255) COLLATE pg_catalog."default",
    CONSTRAINT category_pkey PRIMARY KEY (id)
)

TABLESPACE pg_default;

ALTER TABLE public.category
    OWNER to wp;

最终编辑:我的问题已得到解答,由于某种原因,我的主键未设置为自动递增,这导致了问题。我相信这是因为我只使用 @Id 注释创建了表,并且在创建后我添加了生成策略(它没有将 id 设置为自动递增。

【问题讨论】:

在 JPA @Entity 中使用 Project Lombok 注释可能会导致错误。在运行您的代码之前,请检查 target 文件夹中的字节码。我在 IntelliJ IDEA 中的 JPA 实体上使用 @Data 注释时出错您确定需要 @NoArgsConstructor 吗? 您如何尝试使用代码或 API 请求/调用添加产品?你可以添加代码吗?顺便说一句,我将 Postgres 与 GenerationType.IDENTITY 一起使用,效果很好。 @BinyaminRegev 我知道来自 Lombok 的 @Data 注释会导致问题,这就是我使用 @Getter@Setter 注释的原因(它们不会导致问题,我也使用它们在其他 2 个课程上,他们工作正常没问题)。我还需要@NoArgsConstructor,因为 Hibernate 需要这种类型的构造函数才能创建实体。 - 我用请求添加代码,我会将代码添加到我原来的问题中。 【参考方案1】:

要使其正常工作,您必须更改 Product 表中的某些内容。

@GeneratedValue(strategy = GenerationType.IDENTITY) 仅在您的 ID 列是 SERIAL 类型时才有效。

检查 ID 列是否为该类型。示例:

CREATE TABLE Product(
    id SERIAL NOT NULL,
    name VARCHAR(20),
    etc...
)

【讨论】:

对不起,我是 Spring Data JPA 的新手,我在哪里可以看到您发布的那个 SQL? 放松没问题,你需要检查你的Product表的DDL,进入PostgreSQL数据库 好的,现在我看到了,它没有SERIAL 标签或自动递增逻辑。我还将它与其他表进行了比较,它的构造肯定不同。我编辑了我的原始帖子。你知道这是怎么发生的吗?为什么当我更改注解时,没有为 SQL 实现更改? 太棒了!你只需要从其他表中复制逻辑(只是将id列的类型修改为serial)。 如果他们想要如图所示的 64 位版本,最好使用 bigserial

以上是关于错误:关系 xxx 的“id”列中的空值违反非空约束 - Spring Data JPA的主要内容,如果未能解决你的问题,请参考以下文章

在带有 postgres 数据库的 jbpm 6.5.0Final 中出现错误:“id”列中的空值违反了非空约束

Django - 列中的空值违反了 Django Admin 中的非空约束

“last_login”列中的空值违反非空约束

从 CSV 填充 postgres 表列时出现非空约束错误

SQLSTATE [23502]:非空违规:7 Laravel API 错误

如何忽略 PostgreSQL 窗口函数中的空值?或返回列中的下一个非空值