Springboot 2 CrudRepository.save总是抛出ConstraintViolationException

时间:2018-11-12 15:25:20

标签: java hibernate spring-boot spring-data-jpa

在我的项目中,我已将Springboot版本从1.4.3.RELEASE迁移到2.1.0.RELEASE。之后,CrudRepository.save()总是抛出org.hibernate.exception.ConstraintViolationException:无法执行语句。

这是我在日志中看到的:

o.h.e.j.s.SqlExceptionHelper[m: SQL Error: 1062, SQLState: 23000
o.h.e.j.s.SqlExceptionHelper[m: Duplicate entry '11' for key 'PRIMARY'
o.h.i.ExceptionMapperStandardImpl[m: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement

这是我要保存的实体。

@Getter
@Setter
@Entity
@Table(name = "project_m")
public class Project {

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

    @Column(name = "name" , nullable = false)
    private String name;

    //other fields

}

3 个答案:

答案 0 :(得分:2)

从Springboot 1.4.3.RELEASE更改为2.1.0。RELEASE是内部的 Hibernate 版本,从 5.0 5.3

而这已经改变了SequenceGenerator的工作方式,在策略为GenerationType.AUTO的情况下(如您的情况)使用了该方法。 enter image description here

链接到hibernate migration doc here

有关休眠生成策略here的更多详细信息。

我的猜测是有2个并行会话插入到该表中,并且它们现在都共享序列号的本地副本,这会造成冲突。不过不确定!

我的建议是将策略更改为GenerationType.SEQUENCE并尝试。

答案 1 :(得分:2)

ConstraintViolationException的发生是由于您违反了SQL数据库的主键约束 在SQL中,主键是用于标识记录的唯一键,当您尝试向主列中插入重复值时,数据库将引发异常。 进而由休眠状态传递给您的代码,这就是此异常的原因。

从Springboot 1.4.3.RELEASE到2.1.0.RELEASE Hibernate版本从5.0更新到5.3。

从Hibernate 5.0版开始,Hibernate解释AUTO生成类型的方式已更改

如果使用strategy="AUTO",则Hibernate将生成一个名为hibernate_sequence的表,以提供ID序列的下一个数字。您可能忘记了将自动增量功能添加到表的PK中。

另一种解决方法是在strategy="AUTO"后面加上注解

@Id
@GeneratedValue(
    strategy= GenerationType.AUTO, 
    generator="native"
)
@GenericGenerator(
    name = "native", 
    strategy = "native"
)
private Long id;

您可以使用生成策略strategy="IDENTITY"来强制使用SQL中提供的AutoIncrement功能,并避免创建表。

请检查here以获得更多见解

答案 2 :(得分:1)

我通过在hibernate_sequence表中设置一个较大的值来解决此问题。我看到重复的主键错误中的主键值是从名为hibernate_sequence的表中生成的。

当我们在实体中设置GenerationType.AUTO时,Hibernate将基于Hibernate方言选择生成策略。在旧版本中,Hibernate选择GenerationType.IDENTITY作为MySQL数据库的默认值。

现在它选择使用数据库表生成主键的GenerationType.TABLE