【发布时间】:2018-11-09 20:20:34
【问题描述】:
我有以下问题。我有 2 个实体,电影和演员。
一部电影有多个演员,但一个演员可以出演多部电影。现在,当我尝试添加 2 部具有共同演员的电影时,就会出现问题。
假设我添加了 deadpool,然后我添加了 deadpool 2。当我添加第二部电影时,我收到以下错误:
语句被中止,因为它会导致唯一或主键约束中的重复键值
现在这是有效的,因为 jpa 正在将一个参与者插入到已经存在的数据库中。我不知道如何解决这个问题,我从 TheMovieDatabase 获取 id,我不想在我的数据库中有重复的 Actor。
电影:
@Entity(name = "Movie")
public class Movie {
//instance variables
@Positive
@Id
private long tmdbId;
...
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "movie_actor",
joinColumns = @JoinColumn(name = "movie_tmdbid"),
inverseJoinColumns = @JoinColumn(name = "actor_id")
)
private Set<Actor> actors = new HashSet<>();
...
演员:
@Entity(name = "Actor")
public class Actor {
@Id
private long id;
...
@ManyToMany(mappedBy = "actors")
private Set<Movie> movies = new HashSet<>();
Jpa 添加方法
public void addMovie(Movie movie) {
try {
//open connection
openConnection();
//check
if (movie == null) {
throw new DatabaseException("You cannot add an empty movie");
}
//contains only looks in the current persistence context
if (entityManager.find(Movie.class,movie.getTmdbId()) != null) {
throw new MovieAlreadyExistsException("This movie already exists!");
}
//begin transaction
entityManager.getTransaction().begin();
//add movie & commit
entityManager.persist(movie);
entityManager.getTransaction().commit();
}catch (MovieAlreadyExistsException error){
throw new MovieAlreadyExistsException(error.getMessage(),error);
} catch (Exception error) {
throw new DatabaseException(error.getMessage(), error);
} finally {
closeConnection();
}
}
设置演员的方法:它将从 TheMovieDatabase 中获取演员,而 addMovie 是来自 jpa 在外观后面的演员。
//add a movie
@PostMapping(value = "/add")
public String saveMovie(@ModelAttribute("movie") @Valid Movie movie, BindingResult result) {
...
try{
//set actors
Set<Actor> actors = new HashSet<>(mediaService.getMovieActors(movie.getTmdbId()));
movie.setActors(actors);
//add movie with actors
movieService.addMovie(movie);
堆栈跟踪:
内部异常:org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException:语句被中止,因为它会导致唯一或主键约束或唯一索引中的重复键值由定义的“SQL180530224955890”标识'演员'。 错误代码:20000 呼叫:插入演员(ID、MOVIECHARACTER、姓名、个人资料)值(?、?、?、?) bind => [4个参数绑定] 查询:InsertObjectQuery(model.movie.actor.Actor@d681)] 有根本原因 错误 23505:该语句已中止,因为它会导致在“ACTOR”上定义的“SQL180530224955890”标识的唯一或主键约束或唯一索引中出现重复键值。 在 org.apache.derby.client.am.ClientStatement.completeExecute(未知来源) 在 org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(未知来源) 在 org.apache.derby.client.net.NetStatementReply.readExecute(未知来源) 在 org.apache.derby.client.net.StatementReply.readExecute(未知来源) 在 org.apache.derby.client.net.NetPreparedStatement.readExecute_(未知来源) 在 org.apache.derby.client.am.ClientPreparedStatement.readExecute(未知来源) 在 org.apache.derby.client.am.ClientPreparedStatement.flowExecute(未知来源) 在 org.apache.derby.client.am.ClientPreparedStatement.executeUpdateX(未知来源) 在 org.apache.derby.client.am.ClientPreparedStatement.executeUpdate(未知来源) 在 org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:895) 在 org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:967) 在 org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:637) 在 org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:564) 在 org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2093) 在 org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:309) 在 org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:270) 在 org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:256) 在 org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:405) 在 org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165) 在 org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180) 在 org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:502) 在 org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80) 在 org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90) 在 org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:314) 在 org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58) 在 org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911) 在 org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:810) 在 org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108) 在 org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85) 在 org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2979) 在 org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892) 在 org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874) 在 org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1824) 在 org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:227) 在 org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:194) 在 org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:139) 在 org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4384) 在 org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1491) 在 org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1581) 在 org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:278) 在 org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1218) 在 org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:134) 在 model.db.types.MovieDatabaseJpa.addMovie(MovieDatabaseJpa.java:66) 在 model.MovieService.addMovie(MovieService.java:19) 在 web.controller.MovieController.saveMovie(MovieController.java:72) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) 在 org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) 在 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776) 在 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) 在 org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
谁能指出我正确的方向? 谢谢!
【问题讨论】:
-
您应该发布异常的完整堆栈跟踪以及将
Actors 添加到正在保存的Movie的代码。 -
@BheshGurung 完成
-
似乎它正在尝试插入刚刚检索到的
Actors。试试这个 - 而不是在saveMovie中获取和设置Actors,而是在addMovie中执行此操作,以便检索Actors 和保存Movie发生在同一个 Hibernate 会话/事务中。 -
此外,您(手动)处理连接/会话/事务的方式,例如在您的
addMovie方法中,是一种非常糟糕的做法,尤其是当您使用像 Spring 这样的框架时。 -
@BheshGurung 该服务正在从 TheMovieDatabase api 检索演员,并且未在 jpa 事务中完成。当 jpa 事务发生时,演员已经设置在电影对象 Connection 中,是的,我知道,但它是针对学校原型的。
标签: java spring-mvc jpa orm