【问题标题】:Hibernate: ERROR: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index休眠:错误:该语句被中止,因为它会导致唯一或主键约束或唯一索引中的重复键值
【发布时间】:2019-03-16 14:43:01
【问题描述】:

我是 SQL 和 Hibernate 的新手,需要以下方面的帮助:

实体产品具有(OneToMany)实体类别,其中包含一些选项(列表)。 我希望在保存产品时将其保存(如果不存在),否则进行更新。此外,在保存产品时,如果类别不存在,我需要保存类别。删除/更新产品时,不应删除/更新类别。

当我尝试为类别 id 设置 @GeneratedValue 时,每次运行应用程序时,产品都会更新,但会重新插入类别(使用不同的 id,而不删除以前的 id)。 然后我尝试了下面的代码(类别名称为@Id,因为我知道该名称是唯一的)但随后我得到了您看到的错误。

我做错了什么?我搜索了 Google 和 stackoverflow,但找不到合适/足够简单的解决方案。

hibernate.cfg.xml:

 <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
        <!-- Echo the SQL to stdout -->
        <property name="show_sql">true</property>
        <!-- Set the current session context -->
        <property name="current_session_context_class">thread</property>
        <!-- Drop and re-create the database schema on startup create-drop-->
        <property name="hbm2ddl.auto">update</property>
        <!-- dbcp connection pool configuration -->
        <property name="hibernate.dbcp.initialSize">5</property>
        <property name="hibernate.dbcp.maxTotal">20</property>
        <property name="hibernate.dbcp.maxIdle">10</property>
        <property name="hibernate.dbcp.minIdle">5</property>
        <property name="hibernate.dbcp.maxWaitMillis">-1</property>

        <mapping class="main.Category" />
        <mapping class="main.Product" />

        <mapping class="main.Warehouse" />

...

产品实体:

@Entity
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private int pid;
    private String pName;
    @OneToMany(cascade=CascadeType.ALL,orphanRemoval = true )
    private List<Category> categories;

类别实体:

@Entity
public class Category implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id 
    private Integer catid;
    private String cname;
    @ElementCollection
    private List<String>

公共类 MainApp {

private static SessionFactory sessionFactory;

public static void main(String[] args) {

    @SuppressWarnings("unchecked")
    List<String> options1 = new ArrayList();
    options1.add("option11");
    options1.add("option12");

    @SuppressWarnings("unchecked")
    List<String> options2 = new ArrayList();
    options2.add("option21");
    options2.add("option22");

    Category cat1 = new Category();
    cat1.setCatid(1);
    cat1.setCname("cat1");
    cat1.setcOptions(options1);

    Category cat2 = new Category();
    cat2.setCatid(2);
    cat2.setCname("cat2");
    cat2.setcOptions(options2);

    @SuppressWarnings("unchecked")
    List<Category> categories1 = new ArrayList<>();
    categories1.add(cat1);
    categories1.add(cat2);

    Product product1 = new Product();
    product1.setPid(1);
    product1.setpName("prod1");
    product1.setCategories(categories1);

    @SuppressWarnings("unchecked")
    List<Category> categories2 = new ArrayList<>();
    categories2.add(cat1);

    Product prod2 = new Product();
    prod2.setPid(2);
    prod2.setpName("prod2");
    prod2.setCategories(categories2);

    Warehouse w1 = new Warehouse(1, "s1");
    Warehouse w2 = new Warehouse(2, "s2");

    boolean saveWarehouse = true;
    boolean testAdd = true;
    boolean testDel = false;
    sessionFactory = new Configuration().configure().buildSessionFactory();
    try (Session session = sessionFactory.openSession()) {

        if (testAdd) {
            saveProduct(product1);
            saveProduct(prod2);
        }
        if (testDel) {
            session.beginTransaction();
            session.delete(prod2);
            session.getTransaction().commit();
            session.close();
        }
        if (saveWarehouse) {
            session.beginTransaction();
            session.saveOrUpdate(w1);
            session.saveOrUpdate(w2);
            session.getTransaction().commit();
            session.close();
        }

    }
    System.out.println("PROCESS COMPLETED");
}

public static void saveProduct(Product p) {
    try (Session session = sessionFactory.openSession()) {
        session.beginTransaction();
        session.saveOrUpdate(p);
        session.getTransaction().commit();
        session.close();
    }
}

}

为了节省空间,省略了 Getter 和 Setter。

输出:

Hibernate: alter table Product_Category drop constraint UK_4ipwbaqj6eduy9ca1yi22afph
Hibernate: alter table Product_Category add constraint UK_4ipwbaqj6eduy9ca1yi22afph unique (categories_cname)
Hibernate: select product_.pid, product_.pName as pName2_2_ from Product product_ where product_.pid=?
Hibernate: select category_.cname from Category category_ where category_.cname=?
Hibernate: select category_.cname from Category category_ where category_.cname=?
Hibernate: delete from Product_Category where Product_pid=?
Hibernate: delete from Category_cOptions where Category_cname=?
Hibernate: delete from Category_cOptions where Category_cname=?
Hibernate: insert into Product_Category (Product_pid, categories_cname) values (?, ?)
Hibernate: insert into Product_Category (Product_pid, categories_cname) values (?, ?)
Hibernate: insert into Category_cOptions (Category_cname, cOptions) values (?, ?)
Hibernate: insert into Category_cOptions (Category_cname, cOptions) values (?, ?)
Hibernate: insert into Category_cOptions (Category_cname, cOptions) values (?, ?)
Hibernate: insert into Category_cOptions (Category_cname, cOptions) values (?, ?)
Hibernate: select product_.pid, product_.pName as pName2_2_ from Product product_ where product_.pid=?
Hibernate: select category_.cname from Category category_ where category_.cname=?
Hibernate: insert into Product (pName, pid) values (?, ?)
Hibernate: insert into Product_Category (Product_pid, categories_cname) values (?, ?)
Mar 16, 2019 4:08:17 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 20000, SQLState: 23505
Mar 16, 2019 4:08:17 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: 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 'UK_4IPWBAQJ6EDUY9CA1YI22AFPH' defined on 'PRODUCT_CATEGORY'.
Mar 16, 2019 4:08:17 PM org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl release
INFO: HHH000010: On release of batch it still contained JDBC statements
Mar 16, 2019 4:08:17 PM org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure
ERROR: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1490)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:515)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3348)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2519)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
    at main.MainApp.saveProduct(MainApp.java:96)
    at main.MainApp.main(MainApp.java:72)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1340)
    at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1484)
    ... 10 more
Caused by: 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 'UK_4IPWBAQJ6EDUY9CA1YI22AFPH' defined on 'PRODUCT_CATEGORY'.
    at org.apache.derby.client.am.SQLExceptionFactory.getSQLException(Unknown Source)
    at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
    at org.apache.derby.client.am.ClientPreparedStatement.executeUpdate(Unknown Source)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
    ... 18 more
Caused by: ERROR 23505: 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 'UK_4IPWBAQJ6EDUY9CA1YI22AFPH' defined on 'PRODUCT_CATEGORY'.
    at org.apache.derby.client.am.ClientStatement.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.ClientPreparedStatement.readExecute(Unknown Source)
    at org.apache.derby.client.am.ClientPreparedStatement.flowExecute(Unknown Source)
    at org.apache.derby.client.am.ClientPreparedStatement.executeUpdateX(Unknown Source)
    ... 20 more
[ERROR] Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:404)
    at org.apache.commons.exec.DefaultExecutor.execute(DefaultExecutor.java:166)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine(ExecMojo.java:764)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine(ExecMojo.java:711)
    at org.codehaus.mojo.exec.ExecMojo.execute(ExecMojo.java:289)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
    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)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

【问题讨论】:

  • 不要使用功能名称是ID。这将阻止您修改类别的名称。 ID 必须是唯一的,但也是不可变的。如果一个类别已经存在,那么用户通常应该在一个类别中选择它,因此它已经有了一个 ID。如果他创建了一个,那么它将没有任何 ID。
  • “这将阻止您修改类别的名称”。这是个好的观点!谢谢你。但是当我使用自动生成的 id 时,我遇到了我提到的问题:“当我尝试为类别 id 设置 @GeneratedValue 时,每次运行应用程序时,产品都会更新,但类别会重新插入(使用不同的id,不删除之前的id)。"
  • 如果类别被重新插入,这意味着您告诉 Hibernate 这样做,通过传递没有 ID 但与实际现有类别具有相同名称的类别。如果使用 Hibernate 保存没有 ID 的实体,Hibernate 认为需要插入它,因为它还没有 ID。
  • 不,事实并非如此。正如我所说,我有:@Id @GeneratedValue private Integer id;所以,Id一直存在。问题是虽然类别是相同的,但每次我运行应用程序时都会创建一个新的 id,所以 Hibernate 再次插入具有不同 Id 的相同类别(自动生成的那些)。自从我注释掉后,您可以在代码中看到我作为 id 的内容。
  • class 定义了一个属性,它是一个自动生成的 ID。如果您保存的 object 的 id 为空(即没有 ID,用英文表示),则 Hibernate 认为它尚不存在于数据库中,因此将其插入。

标签: java hibernate cascade


【解决方案1】:

我在完全相同的数据库供应商上遇到了这个异常。 罪魁祸首是这一行:

@Column(nullable = false, unique = true)
private int fieldName = -1;

因此,当传入数据时,它强制 DB 属性是唯一的 不满足这个约束。 在这种情况下,它必须设置为:

unique = false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-07
    • 2016-09-21
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    相关资源
    最近更新 更多