JPA内部工作原理。 MySQLIntegrityConstraintViolationException

| 我真的很难理解为什么会出现此错误。我指的是我的艺术家实体中的GLOBAL_ID字段。我想我一定缺少有关JPA内部工作方式的信息。让我们考虑这两个实体。
@Entity
public class Music {
   @Id
   private String MYID;
   @Column(unique=true)
   private String GLOBAL_ID;
   @ManyToOne(cascade=CascadeType.ALL) @JoinColumn(name=\"ARTIST_ID\")
   private Artist artist;
}


@Entity
public class Artist {
   @Id
   private String MYID;
   @Column(unique=true)
   private String GLOBAL_ID;
}
在我尝试坚持之前,音乐。我已经按艺术家GLOBAL_ID查找数据库。如果存在,我会从数据库获得实例,并将音乐人设置为音乐人。然后,我执行EntityManager.merge(Music)。因此,即使我从DB获得了这位艺术家,并且将新来的艺术家换成了现有的艺术家,我还是会感到疲倦,因为随着Music的出现,实体经理将试图再次坚持下去。所以,我做了不同的事情... 我进行了歌手查找,当数据库中有一个具有相同GLOBAL_ID的歌手时,我将“音乐”中的“歌手”字段设置为null并合并了“音乐”。之后,我得到了受管理的音乐实体,并设置了我以前查找过的现有艺术家。没有成功... 我正在像这样合并....音乐= EntityManager.merge(音乐) 我整天都经过这段代码,找不到我做错了什么。 JPA是否不应该尝试保留并已管理实体?我不知道。如果有人可以帮助我,我将不胜感激。 除了已经尝试的数万亿种不同的尝试之外,我还尝试从DB中分离出艺术家,但后来无法将其重新合并。 预先感谢您的帮助, 问候, 这是处理持久性和下面的堆栈跟踪的代码。 好的,我将尝试发布并解释... 这是一个导入bean,它在循环中从目录中读取mp3文件,从中获取ID3标签,并从中构造Music类。 这是处理JPA的代码。我已经修改了几次,以消除错误。现在,当音乐是现有艺术家的新作品时,我从音乐中删除了艺术家参考,并且在音乐合并之后,将其链接到现有艺术家。在此之前,我只是将艺术家换成现有的艺术家,并且一直坚持下去。  我可以看到所有具有令人满意的ID的日志消息。我的意思是,我可以注意到艺术家查询找到了现有的艺术家。以下是堆栈跟踪。再次感谢您看一下...
                    if (mediaMusic.getMYID() == null || mediaMusic.getMYID().equals(\"\")) {

                        Music oldMusic = null;
                        Query mq = null;
                        if (mediaMusic.getGLOBAL_ID() != null && !mediaMusic.getGLOBAL_ID().equals(\"\")) {
                            mq = em.createNamedQuery(Music.QUERY_FIND_BY_GLOBAL_ID);
                            mq.setParameter(Music.QUERY_PARAMETER_GLOBAL_ID, mediaMusic.getGLOBAL_ID());
                            Iterator musicsSameGLID = mq.getResultList().iterator();
                            if (musicsSameGLID.hasNext()) {
                                oldMusic = (Music) musicsSameGLID.next();
                            }
                        } else if (mediaMusic.getTitle() != null && !mediaMusic.getTitle().equals(\"\")) { 
                            mq = em.createNamedQuery(Music.QUERY_FIND_BY_TITLE);
                            mq.setParameter(Music.QUERY_PARAMETER_TITLE, mediaMusic.getTitle().toUpperCase());
                            Iterator existingMusics = mq.getResultList().iterator();
                            Music existingMusic = null;
                            while (existingMusics.hasNext()) {
                                existingMusic = (Music) existingMusics.next();
                                if (mediaMusic.getArtist() != null && existingMusic.getArtist() != null
                                        && mediaMusic.getArtist().getGLOBAL_ID() != null
                                        && mediaMusic.getArtist().getGLOBAL_ID().equals(existingMusic.getArtist().getGLOBAL_ID())) {
                                    oldMusic = existingMusic;
                                    break;
                                } else if (existingMusic.getArtist() != null && mediaMusic.getArtist() != null
                                        && existingMusic.getArtist().getName().equals(mediaMusic.getArtist().getName())) {
                                    oldMusic = existingMusic;
                                    break;
                                }
                            }
                        }
                        if (oldMusic != null) {
                            mediaMusic = oldMusic;
                        }
                    }

                    // IF IT IS A NEW ARTIST, CHECKING FOR EXISTING ONE
                    if (mediaMusic.getArtist() != null 
                            && (mediaMusic.getArtist().getMYID() == null || mediaMusic.getArtist().getMYID().equals(\"\"))) {

                        if (mediaMusic.getArtist().getGLOBAL_ID() != null
                                && !mediaMusic.getArtist().getGLOBAL_ID().equals(\"\")) {
                            Query aq = em.createNamedQuery(Artist.QUERY_FIND_BY_GLOBAL_ID);
                            aq.setParameter(Artist.GLOBAL_ID_QUERY_PARAMETER, mediaMusic.getArtist().getGLOBAL_ID());
                            Iterator existingArtists = aq.getResultList().iterator();
                            if (existingArtists.hasNext()) {
                                // Persiste primeiro sem artista
                                logger.log(Level.INFO, \"Artista {0}, ArtistaGLID: {1} para a musica MYID: {2} Titulo: {3} found in DB\", new Object[]{mediaMusic.getArtist().getName(), mediaMusic.getArtist().getGLOBAL_ID(), mediaMusic.getMYID(), mediaMusic.getTitle()});
                                if (mediaMusic.getMYID() == null || mediaMusic.getMYID().equals(\"\")) {
                                    artistaExistente = (Artist) existingArtists.next();
                                    mediaMusic.setArtist(null);
                                    logger.log(Level.INFO, \"Inserting and removing Artist: New artist is {0}\", mediaMusic.getArtist());
                                } else {
                                    mediaMusic.setArtist((Artist)existingArtists.next());
                                }
                            }
                        }
                    }

        mediaMusic = em.merge(mediaMusic);

        // 20110424 TRYING TO LINK EXISTING ARTIST AFTER MUSIC IN DB
        if (artistaExistente != null)) {
            logger.log(Level.INFO, \"Music already in BD with o MYID: {0}\", mediaMusic.getMYID());
            logger.log(Level.INFO, \"Adding artist {0} MYID: {1}\", new Object[]{artistaExistente.getName(), artistaExistente.getMYID()});
            mediaMusic.setArtist(artistaExistente);
            logger.info(\"After artist had been added to Music\");
        }
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry \'01809552-4f87-45b0-a45b0-afff-2c6f0730a3be\' for key \'GLOBAL_ID\'
        at sun.reflect.GeneratedConstructorAccessor178.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
        at com.mysql.jdbc.Util.getInstance(Util.java:382)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3603)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3535)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1989)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2150)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2333)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2318)
        at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:120)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:789)
        ... 74 more
|#]
[#|2011-04-25T10:32:01.004-0300|SEVERE|oracle-glassfish3.1|co.bmq.media.beans.MediaMaintenanceBean|_ThreadID=53;_Thr$
javax.ejb.EJBException: Transaction aborted
        at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5121)
        at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4894)
        at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2039)
        at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1990)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.jav$
        at $Proxy201.updateMedia(Unknown Source)
        at co.bmq.media.beans.__EJB31_Generated__MediaStorageServiceBean__Intf____Bean__.updateMedia(Unknown Source)
        at co.bmq.media.beans.MediaMaintenanceBean.checkImportDir(MediaMaintenanceBean.java:98)
        at sun.reflect.GeneratedMethodAccessor374.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
        at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManag
er.java:1124)
        at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5367)
        at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:801)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundTimeout(SystemInterceptorProxy.java:149)
        at sun.reflect.GeneratedMethodAccessor373.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:862)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:801)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:371)
        at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5339)
        at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5327)
        at com.sun.ejb.containers.BaseContainer.callEJBTimeout(BaseContainer.java:4033)
        at com.sun.ejb.containers.EJBTimerService.deliverTimeout(EJBTimerService.java:1835)
        at com.sun.ejb.containers.EJBTimerService.access$100(EJBTimerService.java:108)
        at com.sun.ejb.containers.EJBTimerService$TaskExpiredWork.run(EJBTimerService.java:2708)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
        at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:475)
        at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:$
        at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5115)
        ... 37 more
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exce$
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry \'01809552-4f552-4f87-45b0-afff-2c6f0730a3be\' for key \'GLOBAL_ID\'
Error Code: 1062
Call: INSERT INTO ARTIST (MYID, ANNOTATION, COMMENT, COUNTRY, GENDER, LASTDATANORMALIZATIONDATE, LASTUPDATEDON, LIKES, GLOBAL_ID, NAME, SINCEDATE, TAGS, TODATE, TYPE, ENTITY_UID, VERSION) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        bind => [14 parameters bound]
Query: InsertObjectQuery(co.bmq.media.entity.Artist@3741c26)
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:798)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:864)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:583)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:526)
        at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:1729)
        at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:234)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.ja$
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.ja$
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.j$
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:162)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:177)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:$
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.$
        at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:808)
        at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:711)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModif$
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2842)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1521)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1503)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:$
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:$
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:136)
        at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3766)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1404)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.ja$
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1511)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3115)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitO$
        at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListe$
        at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:6$
        at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:437)
        ... 39 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry \'01809552-4f87-45b0-a$
        at sun.reflect.GeneratedConstructorAccessor178.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
        at com.mysql.jdbc.Util.getInstance(Util.java:382)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3603)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3535)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1989)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2150)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2333)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2318)
        at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:120)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:789)
        ... 74 more
    
已邀请:
我认为新Music对象的合并可能在解决现有Artist时感到困惑。如果音乐是新音乐,请尝试调用而不是merge()来调用persist()。     
我想知道为什么您需要在两个表中都包含GLOBAL_ID。您可以像
SELECT m FROM Music m WHERE m.artist.name = :artistName
一样查询。您可以删除GLOBAL_ID并优化逻辑以使其更简单。     
首先,感谢大家的参与。实际上,你们没有足够的细节来发现这些细节,而这是我的项目所特有的。 问题是:我在该对象中具有更多的双向关系,例如...音乐-> AlbumTrack->专辑->艺术家。我的问题是这位艺术家在这里没有修改数据库中存在的那个艺术家,并且通过日志很难发现是哪个对象引起了它。 再次感谢你们     

要回复问题请先登录注册