Java 为什么我会收到 @OneToMany 属性的主键违规?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20805188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why am I getting a Primary Key violation for an @OneToMany property?
提问by Adam
I have an entity:
我有一个实体:
@Entity
public class Student {
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private long id;
@OneToMany
private Set<Course> courses;
}
When I try to persist the first entity of this type it works fine, but then when I try to save a new Student with the same course as the already stored entity it fails. Here is the error:
当我尝试保留这种类型的第一个实体时,它工作正常,但是当我尝试使用与已存储实体相同的课程保存新学生时,它失败了。这是错误:
insert into student_courses (student, courses) values (?, ?) [23505-172]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "UK_1DBE7B943AC44E1B841DA2688EB_INDEX_5 ON PUBLIC.STUDENT_COURSES(COURSES)"; SQL statement:
insert into student_courses (student, courses) values (?, ?) [23505-172]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:83)
at org.h2.index.TreeIndex.add(TreeIndex.java:65)
at org.h2.table.RegularTable.addRow(RegularTable.java:124)
at org.h2.command.dml.Insert.insertRows(Insert.java:126)
at org.h2.command.dml.Insert.update(Insert.java:86)
at org.h2.command.CommandContainer.update(CommandContainer.java:79)
at org.h2.command.Command.executeUpdate(Command.java:235)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:154)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:140)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58)
at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1256)
at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:364)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:356)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:281)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:328)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:158)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy45.save(Unknown Source)
at students.StudentController.createRandomShiur(ShiurimController.java:66)
at shiurim.StudentController.getStudents(StudentController.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:220)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:746)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:687)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:946)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:822)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:680)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1686)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:695)
I am using Spring Data JPA with Hibernate and H2 as the database.
我使用带有 Hibernate 和 H2 作为数据库的 Spring Data JPA。
The application created its own database tables:
该应用程序创建了自己的数据库表:
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
So, why would there be a unique constraint?
那么,为什么会有唯一约束呢?
Update:
更新:
I see that Hibernate added the constraint:
我看到 Hibernate 添加了约束:
Hibernate: alter table student_courses add constraint UK_a8c48f36df374f1293c46699c83 unique (courses)
How do I tell Hibernate not to create that?
我如何告诉 Hibernate 不要创建它?
Thanks!
谢谢!
采纳答案by atamanroman
Since the violation happens in the STUDENT_COURSES
table, it seems like you are trying to persist the same relationship twice. You mapped a Set
, which signals Hibernate that these relationships must occur not more than once. Check the generated DDL for unique indexes on COURSE_ID, STUDENT_ID).
由于违规发生在STUDENT_COURSES
表中,因此您似乎试图两次保持相同的关系。您映射了 a Set
,它向 Hibernate 发出信号,这些关系不能多次出现。检查生成的 DDL 以获取 COURSE_ID、STUDENT_ID 上的唯一索引)。
The reason may be a flaw in your program logic (eg. modifying fields relevant to equals
on Course
s after they are added to the set or a faulty equals
in your Course
entity.
原因可能是您的程序逻辑存在缺陷(例如,在将与equals
on Course
s 添加到集合中后修改相关字段或equals
您的Course
实体中存在错误。
You have to decide yourself (your client in the real world, since this is a business decision), if a Student
can participate in a Course
more than once (e.g. failed the first time).
您必须自己决定(您在现实世界中的客户,因为这是一个商业决策),是否Student
可以Course
多次参与(例如第一次失败)。
回答by bNd
You have to use GenerationType.TABLE
instead of GenerationType.AUTO
. That way, jpa uses a sequence table for id assignment and you may never need to generate sequence or auto-increment values or triggers that lowers portability.
你必须使用GenerationType.TABLE
而不是GenerationType.AUTO
. 这样,jpa 使用序列表进行 id 分配,您可能永远不需要生成降低可移植性的序列或自动递增值或触发器。
回答by Mani
It is not the problem with Sequence / JPA /hibern.As per your log the error happend on student_courses
这不是 Sequence/JPA/hibern 的问题。根据您的日志,错误发生在 student_courses 上
insert into student_courses
UK_1DBE7B943AC44E1B841DA2688EB_INDEX_5
Seems , you have unquie constraint in student_course table with courses. remove that unquie constraint / you may need to add composite of student and courses for unquie constraint not just courses.
似乎,您在带有课程的 student_course 表中有 unquie 约束。删除该 unquie 约束/您可能需要为 unquie 约束添加学生和课程的组合,而不仅仅是课程。
回答by Ari
The is likely that you set
@OneToMany
while you actually have a@ManyToMany
relationship.
这很可能是您
@OneToMany
在实际建立@ManyToMany
关系时设定的。
Assuming that Course
has no autogenerated Id, then there will be a problem as soon as the second student will add a Course with the same name.
Since it is a one to many relationship a new course will be created with the same unique restricted Id
假设Course
没有自动生成的Id,那么只要第二个学生添加一个同名的课程就会出现问题。
由于它是一对多的关系,因此将创建具有相同唯一受限 ID 的新课程