最近在作項目中, hibernate 物理刪除 delete 方法的時候, 爆了詭異的錯誤,java
好比 mysql
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 錯誤。web
一時之間懵逼了。 請教同事 說多是 hibernate的級聯 或者關聯 其餘表的錯誤。spring
隨時可使用邏輯刪除規避這個錯誤, 可是 總是感受有點不服,難度真的是 hibernate的BUG ?sql
或者爲何?apache
好比 刪除表 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 表報錯 但是爲何? 我記得 以前 寫代碼的時候 管理 明細表的時候,主表是能夠直接刪除的啊!
因而想辦法 從新這個問題tomcat
有主表 GoodsPackage 和 關聯的明細表 GoodsPackageDetail websocket
正常他們的關聯是這些寫的mvc
主表是這樣 @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 數據 並無一塊兒刪除
因而我 參考 ,換一種寫法 ,去刪除測試app
主表: @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的一方確定是被控方。它有以下四個特色:
一、只有OneToOne、OneToMany、ManyToMany上纔有mappedBy屬性,ManyToOne不存在該屬性。
二、@OneToMany(mapped=「由One的一方指向Many的一方,而且,這個屬性應該等於Many的一方中含有One類的屬性的對象名,不然會出錯」),即主控方中定義的被控方的對象名。
三、關係的主控方(即Many的一方)負責關係的維護,在主控方用到@JoinColumn創建外鍵。
四、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 指定 關係的維護方。