我有以下问题。我有2个实体,电影和演员。
电影有多个演员,但演员可以在多部电影中。现在,当我试图添加两部具有共同角色的电影时,问题就出现了。
我们假设我添加了死区,之后我添加了死区2.当我添加第二部电影时,我收到以下错误:
语句已中止,因为它会在唯一或主键约束中导致重复键值
现在这是有效的,因为jpa正在将actor插入已存在的数据库中。我不知道如何解决这个问题,我从TheMovieDatabase获取了ID,我不希望在我的数据库中有重复的Actors。
MOVIE:
@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:语句已中止,因为它会在唯一或主键约束或由&#39; SQL180530224955890&标识的唯一索引中导致重复键值#39;定义于&#39; ACTOR&#39;。 错误代码:20000 致电:插入ACTOR(ID,MOVIECHARACTER,NAME,PROFILEPICTURE)值(?,?,?,?) bind =&gt; [4个参数绑定] 查询:具有根本原因的InsertObjectQuery(model.movie.actor.Actor@d681)] 错误23505:语句已中止,因为它会在唯一或主键约束或由&#39; SQL180530224955890&#39;标识的唯一索引中导致重复键值。定义于&#39; ACTOR&#39;。 at org.apache.derby.client.am.ClientStatement.completeExecute(Unknown Source) 在org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(未知来源) 在org.apache.derby.client.net.NetStatementReply.readExecute(未知来源) 在org.apache.derby.client.net.StatementReply.readExecute(未知来源) at org.apache.derby.client.net.NetPreparedStatement.readExecute_(未知来源) at org.apache.derby.client.am.ClientPreparedStatement.readExecute(Unknown Source) at org.apache.derby.client.am.ClientPreparedStatement.flowExecute(Unknown Source) 在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) at 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) at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165) at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180) 在org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:502) at 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) at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58) 在org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911) at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:810) at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108) at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2979) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1824) at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:227) at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:194) 在org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:139) at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4384) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1491) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1581) at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:278) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1218) at 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) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at 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)
有人能指出我正确的方向吗? 谢谢!
答案 0 :(得分:0)
我解决了这个问题:
我使用了merge而不是persist,因为如果实体存在,它将更新它,否则插入它。