最近在做项目中, hibernate 物理删除 delete 方法的时候, 爆了诡异的错误,

比如 

org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [update gwqmshop_goods_package_detail set goods_package_id=null where goods_package_id=?]; constraint [null]; nested exception is

总之就是 删除的时候,爆了 其他表的 update 错误。

一时之间懵逼了。 请教同事 说可能是  hibernate的级联 或者关联 其他表的错误。

随时可以使用逻辑删除规避这个错误, 但是 老是感觉有点不服,难度真的是 hibernate的BUG ?

或者为什么?


比如 删除表 ShopCartPackage , 对象里面 关联了 GoodsPackageDetail
以下是关联的地方。

/**
	 * 商品明细
	 */
	@OneToMany(fetch = FetchType.LAZY, cascade = {})
    @JoinColumn(name="goods_package_id", referencedColumnName="goods_package_id")
	@OrderBy("goodsThickness asc,goodsWidth asc")
	private List<GoodsPackageDetail> packageDetails;

报错也是 要 updae GoodsPackageDetail 表报错

可是为什么?  我记得 之前 写代码的时候 管理 明细表的时候,主表是可以直接删除的啊!

于是想办法 重新这个问题

有主表 GoodsPackage 和 关联的明细表 GoodsPackageDetail 

正常他们的关联是这些写的

主表是这样
	 @OneToMany(mappedBy="goodsPackage",fetch=FetchType.LAZY)

	@OrderBy("goodsThickness asc,goodsWidth asc")
	private List<GoodsPackageDetail> details;


明细对象 里面是这样
@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="goods_package_id",updatable=false,nullable=false)
	private GoodsPackage goodsPackage;


这样的写法,我测试的时候, 直接删除 主表 goodsPackage 是没有问题的。删除主表的时候,同时对应明细表GoodsPackageDetail 数据 并没有一起删除

于是我 参考 ,换一种写法 ,去删除测试

主表:

	@OneToMany(fetch = FetchType.LAZY)
	@JoinColumn(name = "goods_package_id", referencedColumnName = "id")
	@OrderBy("goodsThickness asc,goodsWidth asc")
	private List<GoodsPackageDetail> details;

明细表还是一样:
@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="goods_package_id",updatable=false,nullable=false)
	private GoodsPackage goodsPackage;


此时删除主表就报错了,重新了问题了

org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [update gwqmshop_goods_package_detail set goods_package_id=null where goods_package_id=?]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643)
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:103)
	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:518)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633)
	at com.gwqm.platform.goods.service.impl.GoodsPackageServiceImpl$$EnhancerBySpringCGLIB$$6dea54a.deleteDo(<generated>)
	at com.gwqm.ctrl.seller.action.goods.GoodsPackageSellerAction.delete(GoodsPackageSellerAction.java:387)
	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.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:933)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:867)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:951)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:853)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:827)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:394)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.gwqm.base.filter.PageCacheFiler.doFilter(PageCacheFiler.java:72)
	at net.sf.ehcache.constructs.web.filter.Filter.doFilter(Filter.java:86)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.gwqm.base.filter.SecondDomainFilter.doFilter(SecondDomainFilter.java:59)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)
	at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
	at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
	at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at com.gwqm.base.security.support.ShopSecurityExceptionFilter.doFilterHttp(ShopSecurityExceptionFilter.java:88)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:277)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
	at com.gwqm.base.filter.NorLogoutFilter.doFilterHttp(NorLogoutFilter.java:76)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.concurrent.ConcurrentSessionFilter.doFilterHttp(ConcurrentSessionFilter.java:99)
	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
	at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:180)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.gwqm.base.filter.XSSFilter.doFilter(XSSFilter.java:80)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.gwqm.base.filter.PageUrlFilter.doFilter(PageUrlFilter.java:67)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:169)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:514)
	... 111 more
Caused by: java.sql.BatchUpdateException: Column 'goods_package_id' cannot be null
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2054)
	at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1467)
	at com.p6spy.engine.wrapper.StatementWrapper.executeBatch(StatementWrapper.java:98)
	at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:294)
	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
	... 120 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'goods_package_id' cannot be null
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
	at com.mysql.jdbc.Util.getInstance(Util.java:386)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1040)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2794)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2006)
	... 125 more

也就是 少了 mappedBy

mappedBy用于指定具有双向关系的两个实体中哪个实体是被关联处理的,使用mappedBy的一方肯定是被控方。它有如下四个特点:

1、只有OneToOne、OneToMany、ManyToMany上才有mappedBy属性,ManyToOne不存在该属性。

2、@OneToMany(mapped=“由One的一方指向Many的一方,并且,这个属性应该等于Many的一方中含有One类的属性的对象名,否则会出错”),即主控方中定义的被控方的对象名。

3、关系的主控方(即Many的一方)负责关系的维护,在主控方用到@JoinColumn建立外键。

4、mappedBy与JoinColumn/JoinTable总是处于互斥的一方。

以上不难理解就是 没有 mappedBy 时候, 删除 主表的时候 goodsPackage ,

  hibernate会 去解除  明细表 和GoodsPackageDetail 的 关联关系。

那么怎么解除呢,也就是 更新  明细表 GoodsPackageDetail 里面 对应的 主表 字段内容为 null 即可

也就是 会 发SQL update  : update gwqmshop_goods_package_detail set goods_package_id=null where goods_package_id=?

但是 在明细表 GoodsPackageDetail ,这里指定了 主表的关联字段不能为空且不能更新 : nullable=false, updatable=false

@ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="goods_package_id",updatable=false,nullable=false)
    private GoodsPackage goodsPackage;

就算 最终配置了 updatable = true, nullable = true 

还是会爆一样的错误, 因为最终的 更新 where goods_package_id=? 值是null , 取不到 主表的值的。

为什么取不到 也许是 hibernate 的级联 cascade 问题, 字段属性: cascade  ,默认是{} 的,并没有设置值, 这里就不深究了。

也许是写法有那些没有按照 hibernate的规范来吧

因此最终就说 Column 'goods_package_id' cannot be null 

也就是 为了防止  出现 删除的情况,而且 hibernate 的 关联关系的难理解。

最好不要 物理删除。使用逻辑删除了。 或者使用 mappedBy 指定 关系的维护方。

06-20 03:24