在我的项目中,我已将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
}
答案 0 :(得分:2)
从Springboot 1.4.3.RELEASE更改为2.1.0。RELEASE是内部的 Hibernate 版本,从 5.0 到 5.3 。
而这已经改变了SequenceGenerator的工作方式,在策略为GenerationType.AUTO的情况下(如您的情况)使用了该方法。
链接到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