有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java语句被中止,因为它会导致重复的键值

我的JavaEE应用程序的一部分是用户管理。我的开发环境是Windows10、JDK14、Glassfish服务器5.1、ApacheDerbyDB和eclipse持久性JPA上的Netbeans 12.0。目前,在开发阶段,我已经将JPA配置为每当我重新启动服务器时都可以删除和创建表

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
  <persistence-unit name="listserviceDB">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:comp/DefaultDataSource</jta-data-source>
    <properties>
      <property name="eclipselink.ddl-generation.output-mode" value="both"/>
      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
    </properties>
  </persistence-unit>
</persistence>

我有一个实体bean“User”,配置为使用自动生成的实体主键:

public class User implements Serializable {

    private static final long serialVersionUID = 1005L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotNull
    private String userId;
    @NotNull
    private String password;
    ............................
    @NotNull
    private String userRole;
}

每当服务器启动时,我使用JAXB机制用XML文件中的测试数据填充所有表。这是我的用户列表的一个示例。“用户”实体bean的xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<users>
    <user>
        <id>2</id>
        <userId>AMackinzy</userId>
        <password>password</password>
        <userRole>update</userRole>
        <firstName>Adam</firstName>
        <lastName>Mc Keinzy</lastName>
        <officePhone>(718)-815-8110</officePhone>
        <cellPhone>(845)-340-5410</cellPhone>
        <company>MMC</company>
    </user>
    <user>
        <id>3</id>
        <userId>AOzguer23</userId>
        <password>password</password>
        <userRole>consumer</userRole>
        <firstName>Albert</firstName>
        <lastName>Ozgur</lastName>
        <officePhone>(213)-567-2390</officePhone>
        <cellPhone>(917)-301-3491</cellPhone>
        <company>Bernstern</company>
    </user>
    <user>
        <id>1</id>
        <userId>admin</userId>
        <password>password</password>
        <userRole>superadmin</userRole>
        <firstName>Joseph</firstName>
        <lastName>Ottaviano</lastName>
        <officePhone>718-815-8111</officePhone>
        <cellPhone>917-971-6854</cellPhone>
        <company>Lemmen Inc.</company>
    </user>
</users>

当应用程序启动并运行时,我可以通过前端JSF(JavaServerFaces)页面直观地验证数据,一切看起来都很好,这表明JAXB代码已成功地将初始用户数据加载到数据库中。当我尝试从前端JSF页面添加新用户时,可怕的问题就开始了,该页面以以下异常终止:

Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: 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 'SQL201230210444600' defined on 'PERSISTENCE_USER'.
Error Code: 20000
Call: INSERT INTO PERSISTENCE_USER (ID, CELLPHONE, COMPANY, DATEOFBIRTH, FIRSTNAME, LASTNAME, OFFICEPHONE, PASSWORD, USERID, USERROLE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    bind => [10 parameters bound]
Query: InsertObjectQuery(org.me.mavenlistservicedb.entity.User@79460d95)
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:905)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:967)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:637)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:564)
    at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2093)
    at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:309)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:270)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:256)
    at 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)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:502)
    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:314)
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911)

我不确定当“用户”实体利用自动键生成时,为什么会出现此错误,最初的3条数据已经加载到表中,并且自动键生成器已经增加到4(假设JPA开始从index=1生成键)?因此,我通过JSF前端添加的第一个用户(与JAXB共享相同的持久化代码,将XML文件中的初始数据添加到表中)应该被分配id=5

起初,我认为,XML文件(即1)中的Id字段可能与此错误有关,但对于自动密钥生成方案,XML中的Id应该被JPA自动生成的值覆盖

我已经在这个论坛和其他地方读了很多关于这个错误的帖子,但是除了这个错误之外,我没有发现任何与我的情况相同的地方。感谢您对这个错误的根本原因以及我如何在没有应用程序生成主键的情况下修复它所做的清晰解释

更新1:表中的剩余数据

经过彻底的调查,我发现在应用程序启动时,用户表中总是有剩余数据,这违反了我在持久化中选择的删除和创建策略。xml文件(可能是JPA问题?)在这种情况下,当容器调用我的Singleton类@postConstruct注释的方法loadData()从XML文件加载初始数据时,自动密钥生成从1开始,这会导致与具有相同Id的一个剩余行发生冲突。我在服务器启动时修改了代码以删除表中的所有行,问题消失了,但是,我在日志文件中看到以下异常,不会导致应用程序出现任何问题或中断:
Caused by: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.me.mavenlistservicedb.entity.User] is mapped to a primary key column in the database. Updates are not allowed.
    at org.eclipse.persistence.exceptions.ValidationException.primaryKeyUpdateDisallowed(ValidationException.java:2551)
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.writeFromObjectIntoRowWithChangeRecord(AbstractDirectMapping.java:1265)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildRowForUpdateWithChangeSet(ObjectBuilder.java:1773)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1043)
    at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:314)
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
    at 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.commitChangedObjectsForClassWithChangeSet(CommitManager.java:273)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:131)
    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.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3256)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:355)
    at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:158)
    ... 29 more

我绝对没有更新或篡改任何主键,我把这个任务留给了自动生成功能,所以我不知道为什么会出现这个异常?(如果需要源代码,我很乐意提供)


共 (1) 个答案

  1. # 1 楼答案

    在本例中,EclipseJPA根据序列(在数据库中创建的SEQ_GEN序列;它调用该序列上的next value)选择策略,它不是自动生成的列

    因此,在这种情况下,约束冲突异常是可以理解的-首先,在启动时,应用程序会创建3个ID为1、2、3的用户,而不接触序列,然后尝试创建第4个用户,但序列中的第一个值是1

    您可以启用show-sqljpa属性来跟踪发送到数据库的sql