Java 在EJB/JPA环境中优雅地处理约束冲突?
我正在GlassfishV3应用服务器上使用EJB和JPA。我有一个实体类,其中一个字段使用@Column注释强制唯一Java 在EJB/JPA环境中优雅地处理约束冲突?,java,database,jpa,jakarta-ee,ejb-3.0,Java,Database,Jpa,Jakarta Ee,Ejb 3.0,我正在GlassfishV3应用服务器上使用EJB和JPA。我有一个实体类,其中一个字段使用@Column注释强制唯一 @Entity public class MyEntity implements Serializable { private String uniqueName; public MyEntity() { } @Column(unique = true, nullable = false) public String getUniq
@Entity
public class MyEntity implements Serializable {
private String uniqueName;
public MyEntity() {
}
@Column(unique = true, nullable = false)
public String getUniqueName() {
return uniqueName;
}
public void setUniqueName(String uniqueName) {
this.uniqueName = uniqueName;
}
}
当我试图持久化一个对象,并将该字段设置为非唯一值时,当EJB容器管理的事务提交时,我会得到一个异常(如预期的那样)
我想解决两个问题:
1) 我得到的异常是无用的“javax.ejb.EJBException:事务中止”。如果我递归调用getCause()足够多次,我最终会得到更有用的“java.sql.SQLIntegrityConstraintViolationException”,但这个异常是EclipseLink实现的一部分,我不太愿意依赖它的存在
有没有更好的方法可以通过JPA获得详细的错误信息
2) EJB容器坚持记录此错误,即使我捕获并处理它
有没有更好的方法来处理这个错误,防止Glassfish将无用的异常信息塞满我的日志
谢谢
我得到的异常是无用的“javax.ejb.EJBException:事务中止”。(……)
我在我这边做了一个测试(使用GFv3和EclipseLink),我确认了这个行为。完整的堆栈跟踪是:
javax.ejb.EJBException: Transaction aborted
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:4997)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4756)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1955)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1906)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:198)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84)
at $Proxy218.myBusinessMethod(Unknown Source)
at com.stackoverflow.q2522643.__EJB31_Generated__MyEJB__Intf____Bean__.myBusinessMethod(Unknown Source)
at com.stackoverflow.q2522643.MyServlet.doGet(MyServlet.java:28)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:332)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:233)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:450)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:837)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:4991)
... 34 more
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL100326111558470' defined on 'MYENTITY'.
Error Code: -1
Call: INSERT INTO MYENTITY (ID, NAME) VALUES (?, ?)
bind => [2, Duke!]
Query: InsertObjectQuery(com.stackoverflow.q2522643.MyEntity@dba6a9)
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:800)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:866)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:586)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:529)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeCall(AbstractSession.java:914)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:205)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:191)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:334)
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:461)
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.java:286)
at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:675)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:589)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:109)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:86)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2863)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1225)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1207)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1167)
at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:197)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:103)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3260)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1405)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:547)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1510)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3134)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:268)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:157)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:412)
... 36 more
Caused by: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL100326111558470' defined on 'MYENTITY'.
at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:108)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:791)
... 69 more
Caused by: org.apache.derby.client.am.SqlException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL100326111558470' defined on 'MYENTITY'.
at org.apache.derby.client.am.Statement.completeExecute(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown Source)
at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown Source)
... 72 more
javax.ejb.EJBException:事务中止
在com.sun.ejb.containers.BaseContainer.completeNewTx上(BaseContainer.java:4997)
在com.sun.ejb.containers.BaseContainer.postInvokeTx上(BaseContainer.java:4756)
在com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1955)上
位于com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1906)
在com.sun.ejb.containers.ejblocationHandler.invoke(ejblocationHandler.java:198)
在com.sun.ejb.containers.ejblocationHandlerDelegate.invoke(ejblocationHandlerDelegate.java:84)
$Proxy218.myBusinessMethod(未知来源)
在com.stackoverflow.q2522643.\uuuuejb31\uuuuuuuuuuuuuuuuuuuuu生成的\uuuuuuuuuuuuuuuuuuuuuuuuuuu Intf\uuuuuuuuuuuuuuuuuuuuuuuuuuuuu
位于com.stackoverflow.q2522643.MyServlet.doGet(MyServlet.java:28)
位于javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
位于javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
位于org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
位于org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
位于org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
位于org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
位于com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
位于com.sun.enterprise.web.peSessionLockingsStandardPipeline.invoke(peSessionLockingsStandardPipeline.java:85)
位于org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
位于org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:332)
位于org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:233)
位于com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
在com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
位于com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
位于com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
位于com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
位于com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
在com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)上
在com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)上
http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
位于com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
在com.sun.grizzly.SelectionKeyContextTask.call上(SelectionKeyContextTask.java:57)
位于com.sun.grizzly.ContextTask.run(ContextTask.java:69)
位于com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
位于com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
运行(Thread.java:619)
原因:javax.transaction.RollbackException:标记为回滚的事务。
位于com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:450)
位于com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:837)
在com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:4991)
... 34多
原因:异常[EclipseLink-4002](Eclipse持久性服务-2.0.0.v20091127-r5931):org.Eclipse.Persistence.exceptions.DatabaseException
内部异常:java.sql.SQLIntegrityConstraintViolationException:该语句被中止,因为它会导致在“MYENTITY”上定义的“SQL100326111558470”标识的唯一或主键约束或唯一索引中出现重复的键值。
错误代码:-1
调用:插入MYENTITY(ID、名称)值(?、)
绑定=>[2,杜克!]
查询:InsertObjectQuery(com.stackoverflow.q2522643。MyEntity@dba6a9)
位于org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
位于org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:800)
位于org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:866)
位于org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:586)
位于org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:529)
位于org.eclipse.persistence.internal.sessions.AbstractSession.executeCall(AbstractSession.java:914)
位于org.eclipse.persistence.internal.querys.DatasourceCal
<properties>
<property name="eclipselink.logging.level" value="SEVERE"/>
</properties>
@AroundInvoke
public Object interceptor(InvocationContext ic) throws Exception {
Object o = null;
try {
o = ic.proceed();
if (!sessionContext.getRollbackOnly()) {
entityManager.flush();
}
} catch (PersistenceException ex) {
throw new DataStoreException(ex);
}
return o;
}