Hibernate以错误的顺序持久保存我的OneToOne实体

时间:2016-08-25 13:35:38

标签: java hibernate jpa one-to-one

我正在使用Hibernate 4.3.11并尝试将具有一对一关系的实体持久化到另一个实体,但Hibernate似乎试图以错误的顺序执行持久性,从而导致ConstraintViolationException。

以下是我的实体:

@Entity
@Table(name = "B2B_ORDER")
public class Order implements java.io.Serializable
{

    @Id
    @Column(name = "ORDER_NUMBER", unique = true, nullable = false, length = 32)
    private String              orderNumber;

    @OneToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "order")
    private OrderCustomer       orderCustomer;
...
}

@Entity
@Table(name = "B2B_ORDER_CUSTOMER")
public class OrderCustomer implements java.io.Serializable
{

    @Id
    @Column(name = "ORDER_NUMBER")
    private String            orderNumber;

    @OneToOne(optional = false)
    @JoinColumn(name = "ORDER_NUMBER", referencedColumnName =  "ORDER_NUMBER")
    private Order             order;
...
}

我尝试做的就是使用OrderCustomer创建一个Order并保留Order,它也应该创建OrderCustomer记录:

Order order = new Order();
order.setOrderNumber(orderNumber);
...
OrderCustomer orderCustomer = new OrderCustomer();
orderCustomer.setOrder(order);
orderCustomer.setOrderNumber(order.getOrderNumber());
order.setOrderCustomer(orderCustomer);
...
order = orderRepository.save(order);

请注意,orderRepository是一个Spring存储库对象,所有save方法都是调用entityManager.persist(entity)。 当我运行此代码时,由于外键,我在DB中遇到了完整性约束违规:

  

2016-08-24 15:03:00,425 DEBUG [org.hibernate.SQL](http-nio-9090-exec-1)[SqlStatementLogger.java:109]插入b2b_order_customer(customer_profile_txt,order_number)值(? ,?)   2016-08-24 15:03:00,606 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](http-nio-9090-exec-1)[SqlExceptionHelper.java:144] SQL错误:-530,SQLState: 23503   2016-08-24 15:03:00,607 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](http-nio-9090-exec-1)[SqlExceptionHelper.java:146] DB2 SQL错误:SQLCODE = -530 ,SQLSTATE = 23503,SQLERRMC = CWSODEV2.B2B_ORDER_CUSTOMER.B2B_ORDER_CUSTOMER_ORD_NUM_FK,DRIVER = 4.15.100   2016-08-24 15:03:00,612 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl](http-nio-9090-exec-1)[AbstractBatchImpl.java:208] HHH000010:关于批量发布它仍然包含JDBC语句   2016-08-24 15:03:00,721 ERROR [...](http-nio-9090-exec-1)[OrderProcessor.java:188]持久订单时出错:   org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [不适用];约束[null];嵌套异常是org.hibernate.exception.ConstraintViolationException:无法执行语句       在org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)〜[spring-orm-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)〜[spring-orm-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)〜[spring-orm-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)〜[spring-tx-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)〜[spring-tx-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)〜[spring-tx-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor $ CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131)〜[spring-data-jpa-1.9.1.RELEASE.jar!/:na]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)〜[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在com.sun.proxy。$ Proxy111.save(未知来源)〜[na:na]       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)〜[na:1.8.0_91]       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)〜[na:1.8.0_91]       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)〜[na:1.8.0_91]       at java.lang.reflect.Method.invoke(Unknown Source)〜[na:1.8.0_91]       在org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)〜[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)〜[spring-tx-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       ...       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)〜[na:1.8.0_91]       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)〜[na:1.8.0_91]       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)〜[na:1.8.0_91]       at java.lang.reflect.Method.invoke(Unknown Source)〜[na:1.8.0_91]       在org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)〜[spring-aop-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]       在com.sun.proxy。$ Proxy113.save(未知来源)〜[na:na]       ...   引起:com.ibm.db2.jcc.am.SqlIntegrityConstraintViolationException:DB2 SQL错误:SQLCODE = -530,SQLSTATE = 23503,SQLERRMC = CWSODEV2.B2B_ORDER_CUSTOMER.B2B_ORDER_CUSTOMER_ORD_NUM_FK,DRIVER = 4.15.100       在com.ibm.db2.jcc.am.fd.a(fd.java:692)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.fd.a(fd.java:60)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.fd.a(fd.java:127)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.qo.b(qo.java:2412)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.qo.c(qo.java:2395)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.t4.ab.l(ab.java:374)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.t4.ab.a(ab.java:61)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.t4.p.a(p.java:50)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.t4.rb.b(rb.java:220)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.ro.qc(ro.java:3526)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.ro.b(ro.java:4489)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.ro.ic(ro.java:807)〜[db2jcc4-4.15.100.jar!/:na]       在com.ibm.db2.jcc.am.ro.executeUpdate(ro.java:781)〜[db2jcc4-4.15.100.jar!/:na]       在org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)〜[hibernate-core-4.3.11.Final.jar!/:4.3.11.Final]       ...省略了205个常用帧

显然,Hibernate试图在Order之前保持OrderCustomer。这是应该保持的相反顺序。如果考虑OneToMany级联关系,则单个实体将始终在集合之前保留(因此满足外键)。为什么这对一对一不起作用?

感谢。

2 个答案:

答案 0 :(得分:0)

来自JPA参考:

  

对于一对一的双向关系,拥有方   对应于包含相应外键的一侧

在这种情况下,-- Using Python3 CMake Error at /usr/share/cmake-3.5/Modules/FindBoost.cmake:1677 (message): Unable to find the requested Boost libraries. Boost version: 1.59.0 Boost include path: /home/sumit/Documents/Software/boost_1_59_0 Could not find the following static Boost libraries: boost_python3 No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost. Call Stack (most recent call first): CMakeLists.txt:48 (find_package) Boost Paths: Include : /home/sumit/Documents/Software/boost_1_59_0 **Libraries**: /home/sumit/Documents/Software/boost_1_59_0/libs Configuring incomplete, errors occurred! 是拥有方。

  • 您可以将OrderCustomer参数移至cascade并保存OrderCustomer,而不是OrderCustomer

  • 您可以将Order移至@JoinColumn表。

答案 1 :(得分:0)

问题是optional参数。为什么?当此参数为false时,则Hibernate“信任您”并认为该数据库包含相关实体。

您在两个实体中都使用optional = false。这就是问题所在。

当两个实体都有optional = false时:

Hibernate: create table B2B_ORDER (ORDER_NUMBER varchar(32) not null, primary key (ORDER_NUMBER))
Hibernate: create table B2B_ORDER_CUSTOMER (ORDER_NUMBER varchar(32) not null, primary key (ORDER_NUMBER))
Hibernate: alter table B2B_ORDER_CUSTOMER add constraint FKsvt9d7j362lni8mxb83y7cygj foreign key (ORDER_NUMBER) references B2B_ORDER
Hibernate: insert into B2B_ORDER_CUSTOMER (ORDER_NUMBER) values (?)
ERROR :( Order table is empty.

只有OrderCustomer才有optional = false

Hibernate: create table B2B_ORDER (ORDER_NUMBER varchar(32) not null, primary key (ORDER_NUMBER))
Hibernate: create table B2B_ORDER_CUSTOMER (ORDER_NUMBER varchar(32) not null, primary key (ORDER_NUMBER))
Hibernate: alter table B2B_ORDER_CUSTOMER add constraint FKsvt9d7j362lni8mxb83y7cygj foreign key (ORDER_NUMBER) references B2B_ORDER
Hibernate: insert into B2B_ORDER (ORDER_NUMBER) values (?)
Hibernate: insert into B2B_ORDER_CUSTOMER (ORDER_NUMBER) values (?)
SUCCESS :)

只有订单有optional = false

Hibernate: create table B2B_ORDER (ORDER_NUMBER varchar(32) not null, primary key (ORDER_NUMBER))
Hibernate: create table B2B_ORDER_CUSTOMER (ORDER_NUMBER varchar(255) not null, primary key (ORDER_NUMBER))
Hibernate: insert into B2B_ORDER_CUSTOMER (ORDER_NUMBER) values (?)
Hibernate: insert into B2B_ORDER (ORDER_NUMBER) values (?)
SUCCESS :)

您可以看到@OneToOne在拥有方(OrderCustomer)覆盖Order @OneToOne optional参数