我是SQL和Hibernate的新手,我需要以下帮助:
实体产品具有(OneTomany)实体类别,该类别具有一些选项(列表)。我希望保存产品时,如果尚未存在,则保存该产品,否则要更新。另外,保存产品时,如果不存在类别,则需要保存类别。删除/更新产品时,不应删除/更新类别。
当我尝试使用类别ID的@gereratedValue时,每次运行应用程序时,都会更新产品,但是类别已重新插入(使用不同的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();
}
}
}
节省空间,getters&amp;省略了设置器。
输出:
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] ------------------------------------------------------------------------
我在完全相同的数据基供应商上有此例外。罪魁祸首是这条线:
@Column(nullable = false, unique = true)
private int fieldName = -1;
这样,当传入数据时,它强制执行DB属性是唯一的不满足这一约束。在这种情况下,必须将其设置为:
unique = false