デバイス分類削除コード読みだし


に質問
先日、小何はデバイス管理2モジュールでデバイス分類(同時にデバイス分類承認チームを削除)を削除したとき、システムが異常を投げ出した.承認チームが削除に成功し、デバイス分類の削除に成功しなかったことを示します.
  • この問題を明確に説明するために、デバイス分類と承認チームの関係(hibernateマッピング関係)について説明します.
    Hibernateマッピング関係
        --many-to-one-->    
        --one-to-one-->    
    

  • デバイス分類のmanagerコードブロックを削除します.
    com.kedacom.ksoa3.apparatus2.domain.manager.ApparatusTypeManagerImpl.removeApparatusType
    	ApparatusTypePO type = typeDao.getById(typeId);
    	ApparatusTypeTeamPO team = type.getApparatusTypeTeam();
    	if (team != null) {
    		teamDao.remove(team);
    	}
    
    	if (!this.removeApparatusChildrenType(typeId)) {
    		return Message.getMessage(false, "    ,      !");
    	}
     

  • 削除時に異常が発生した情報
    2009-09-11 11:11:58 [ERROR]  Duplicate key or integrity constraint violation message from server: "Cannot delete or update a parent row: a foreign key constraint fails (`ksoa3/apparatus2_type_team`, CONSTRAINT `FK78347D72721385C6` FOREIGN KEY (`type_id`) REFERENCES `apparatus2_type` (`id`))"
    
     <org.hibernate.util.JDBCExceptionReporter> 
    org.hibernate.exception.ConstraintViolationException: could not execute update query
    	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
    	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
    	at org.hibernate.hql.ast.exec.BasicExecutor.execute(BasicExecutor.java:84)
    	at org.hibernate.hql.ast.QueryTranslatorImpl.executeUpdate(QueryTranslatorImpl.java:396)
    	at org.hibernate.engine.query.HQLQueryPlan.performExecuteUpdate(HQLQueryPlan.java:259)
    	at org.hibernate.impl.SessionImpl.executeUpdate(SessionImpl.java:1141)
    	at org.hibernate.impl.QueryImpl.executeUpdate(QueryImpl.java:94)
    	at com.kedacom.common.base.domain.dao.BaseDaoHibernateImpl$1.doInHibernate(BaseDaoHibernateImpl.java:271)
    	at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
    	at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
    	at com.kedacom.common.base.domain.dao.BaseDaoHibernateImpl.executeHql(BaseDaoHibernateImpl.java:264)
    	at com.kedacom.components.tree.manager.impl.TreeNodeManagerImpl.removeTreeNodeAndDescendants(TreeNodeManagerImpl.java:623)
    	at com.kedacom.components.tree.manager.impl.TreeNodeManagerImpl.removeLeaf(TreeNodeManagerImpl.java:596)
    	at com.kedacom.ksoa3.apparatus2.domain.manager.ApparatusTypeManagerImpl.removeApparatusChildrenType(ApparatusTypeManagerImpl.java:103)
    	at com.kedacom.ksoa3.apparatus2.domain.manager.ApparatusTypeManagerImpl.removeApparatusType(ApparatusTypeManagerImpl.java:216)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:585)
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    	at $Proxy73.removeApparatusType(Unknown Source)
    	at com.kedacom.ksoa3.apparatus2.web.controller.ApparatusTypeController.delete(ApparatusTypeController.java:118)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:585)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at com.automatedlogic.domino.sso.DominoLoginFilter.doFilter(DominoLoginFilter.java:87)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
    	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    	at java.lang.Thread
    
    .run(Thread
    
    .java:595)
    Caused by: java.sql.SQLException: Duplicate key or integrity constraint violation message from server: "Cannot delete or update a parent row: a foreign key constraint fails (`ksoa3/apparatus2_type_team`, CONSTRAINT `FK78347D72721385C6` FOREIGN KEY (`type_id`) REFERENCES `apparatus2_type` (`id`))"
    
    
    	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2001)
    	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1168)
    	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1279)
    	at com.mysql.jdbc.Connection.execSQL(Connection.java:2281)
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1825)
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1667)
    	at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:102)
    	at org.hibernate.hql.ast.exec.BasicExecutor.execute(BasicExecutor.java:75)
    	... 57 more
    

  • 異常発生時のSQL情報
    //      tree_node、tree   
    
    
    select type.*, team.* from apparatus2_type type left outer
    
     join apparatus2_type_team team on team.type_id=type.id where type.id=?
    
    select team.* from apparatus2_type_team team where team.type_id=?
    
    delete from apparatus2_type where tree_id='3' and left_node>=2 and right_node<=3
    2009-09-11 11:11:58 [WARN]  SQL Error: 1451, SQLState: 23000 <org.hibernate.util.JDBCExceptionReporter>
    2009-09-11 11:11:58 [ERROR]  Duplicate key or integrity constraint violation message from server: "Cannot delete or update a parent row: a foreign key constraint fails (`ksoa3/apparatus2_type_team`, CONSTRAINT `FK78347D72721385C6` FOREIGN KEY (`type_id`) REFERENCES `apparatus2_type` (`id`))"
    
     <org.hibernate.util.JDBCExceptionReporter> 
    org.hibernate.exception.ConstraintViolationException: could not execute update query
    ...
    
    delete from apparatus2_type_team where id=?
    


  • 分析とデバッグ
  • プロセス全体がSpringトランザクション制御の下にありますか?
  • で調べたところ、Springトランザクション制御の下で行われています.

  • Hibernate SQL印刷を開く
  • では、teamの削除とtypeの削除の順序が私たちが指定したのとは正反対の「例外発生時のSQL情報」が表示されています.どうしてこんなことになったの?私たちは最後に答えを出した.

  • Hibernateのカスケード削除を試み、typeを削除すると同時にteamをカスケード削除する
  • は効果がありません.私たちはsql文を使用してtypeを削除しているので、このsql文はカスケード削除を開始しません.オブジェクトに対する操作のみが、そのプロパティに対するカスケード操作を開始できます.

  • hibernateはSQLの実行順序を変更しました.inverseの問題ですか?
  • (後にinverseの問題ではなくhiberanateがキャッシュをクリーンアップするメカニズムが原因であることが判明した)この推測によれば、teamを削除するときにsessionを手動でクリーンアップすれば、hibernateはSQLの実行順序を変更しないと考えられている.そこで、A p a r a t u s TypeTeamDaoHibernateImplがteamを削除する動作を変更しました(コードを変更した後、問題解決):
    com.kedacom.ksoa3.apparatus2.domain.dao.ApparatusTypeTeamDaoHibernateImpl.remove
    	public boolean remove(ApparatusTypeTeamPO team){
    		super.remove(team);
    		super.getHibernateTemplate().flush();
    		return true;
    	} 



  • 最後に、Hibernateが私たちのsqlの実行順序を変更する理由を説明します.Hibernate Sessionがクリーンアップするとき、sqlの実行順序を実行します.
    Hibernate Sessionはキャッシュをクリーンアップするとき、Sql文をどのような順序で実行しますか?http://www.wangchao.net.cn/bbsdetail_854253.html
  • アプリケーションがSession.Save()メソッドを呼び出す順番に、エンティティを挿入するすべてのinsert文を実行します.
  • エンティティを更新するすべてのupdate文を実行します.
  • コレクションを削除するdelete文をすべて実行します.
  • は、集合要素を更新、削除、挿入するすべてのsql文を実行する.
  • は、セットを挿入するすべてのinsert文を実行する.
  • アプリケーションがSesson.delete()メソッドを呼び出す順に、エンティティを削除するdelete文をすべて実行します.

  • 上記の説明によると、私たちのコードではまず2つのgetから2つのselect文が生成されます.そして私たちのコードdeleteはteamオブジェクトです.delete typeのsql文をもう1つ実行します(私たちのr e m o v eApparatusChildrenTypeは実際にはsql文でtypeオブジェクトを削除します).
    typeはteamの属性でもあるため、4番目の「集合要素を更新、削除、挿入するすべてのsql文を実行する」に従ってdelete typeのsql文を先に実行し、6番目の「アプリケーション呼び出しSesson.delete()メソッドの前後順に、エンティティを削除するすべてのdelete文を実行する」に従ってdelete teamオブジェクトの文を実行します.