代码之家  ›  专栏  ›  技术社区  ›  vmg

Struts2+休眠:无法捕获ConstraintVolationException

  •  1
  • vmg  · 技术社区  · 15 年前

    我正在用Struts2.2.1和Hibernate3编写Web应用程序。当我试图删除实体时,我遇到了问题,这个实体与其他实体有一对多的关系。我希望实现这样的场景:1)打开会话->2)尝试删除实体3)提交4)捕获ConstraintVolationException,然后回滚并向用户显示消息,说明另一个表中存在相关项。但我无法捕获ConstraintViolationException!这是我的休眠配置:

    <?xml version="1.0" encoding="UTF-8"?>
    

    "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
      <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
        <property name="hibernate.connection.url">jdbc:derby:c:\soft\db\simple.db;create=true</property>
        <property name="hibernate.connection.username">app</property>
        <property name="hibernate.connection.password">app</property>
        <property name="current_session_context_class">thread</property>
        <property name="cache.provider_class">
            org.hibernate.cache.NoCacheProvider
        </property>
        <property name="show_sql">true</property>
        <property name="hbm2ddl.auto">update</property>
        <property name="hibernate.connection.pool_size">1</property>
        <mapping resource="bytes/ewt/model/Shortcuts.hbm.xml"/>
        <mapping resource="bytes/ewt/model/Categories.hbm.xml"/>
      </session-factory>
    </hibernate-configuration>
    

    类别类的映射:

        <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <!-- Generated 27 ???? 2010 22:43:18 by Hibernate Tools 3.2.1.GA -->
    <hibernate-mapping>
      <class catalog="ewt" name="bytes.ewt.model.Categories" table="categories">
        <id name="id" type="java.lang.Long">
          <column name="ID"/>
          <generator class="identity"/>
        </id>
        <property name="categoryName" type="string">
          <column length="200" name="CategoryName" not-null="true" unique="true"/>
        </property>
        <set inverse="true" name="shortcutses">
          <key>
            <column name="category_id" not-null="true"/>
          </key>
          <one-to-many class="bytes.ewt.model.Shortcuts"/>
        </set>
      </class>
    </hibernate-mapping>
    

    我在Web筛选器中的会话管理:

        package bytes.ewt.web.filters;
    
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.hibernate.SessionFactory;
    import org.hibernate.StaleObjectStateException;
    import bytes.ewt.HibernateUtil;
    
    
    
    public class HibernateSessionRequestFilter implements Filter {
    
        private SessionFactory sf;
        private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);
    
        public void doFilter(ServletRequest request,
                             ServletResponse response,
                             FilterChain chain)
                throws IOException, ServletException {
    
            try {
                if (!sf.getCurrentSession().isOpen())
                    sf.openSession();
    
                sf.getCurrentSession().beginTransaction();
    
                // Call the next filter (continue request processing)
                chain.doFilter(request, response);
    
                // Commit and cleanup
                if (sf.getCurrentSession().getTransaction().isActive())
                    sf.getCurrentSession().getTransaction().commit();
    
            } catch (StaleObjectStateException staleEx) {
                log.error("This interceptor does not implement optimistic concurrency control!");
                log.error("Your application will not work until you add compensation actions!");
                // Rollback, close everything, possibly compensate for any permanent changes
                // during the conversation, and finally restart business conversation. Maybe
                // give the user of the application a chance to merge some of his work with
                // fresh data... what you do here depends on your applications design.
                throw staleEx;
            } catch (Throwable ex) {
                // Rollback only
                ex.printStackTrace();
                try {
                    if (sf.getCurrentSession().getTransaction().isActive()) {
                        //log.debug("Trying to rollback database transaction after exception");
                        sf.getCurrentSession().getTransaction().rollback();
                    }
                } catch (Throwable rbEx) {
                    //log.error("Could not rollback transaction after exception!", rbEx);
                    rbEx.printStackTrace();
                }
    
                // Let others handle it... maybe another interceptor for exceptions?
                throw new ServletException(ex);
            }
        }
    
        public void init(FilterConfig filterConfig) throws ServletException {
            log.debug("Initializing filter...");
            log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
            sf = HibernateUtil.getSessionFactory();
        }
    
        public void destroy() {}
    
    }
    

    当我尝试用struts2操作()删除类别时,我添加了System.out来调试Purose:

    public String delete() throws Exception{
        if (id == null || id.length() == 0){
            addActionError(getText("categories.update.id.empty"));
            return "operation_done";
        }
        CategoriesManager mgr = ApplicationSupervisor.getInstance().getCategoriesManager();
        try{
            mgr.remove(Long.parseLong(id));
            mgr.commit();
        } catch(ConstraintViolationException ex){
            System.out.println("##Action-catch");
            //addActionError(getText("categories.in.use"));
            return "operation_done";
        } catch(Exception ex){
            System.out.println("##Action-all-catch: "+ex.getMessage() + ex.getClass() );
        }
    
        return "operation_done";
    }
    

    以及经理的提交代码:

    public void commit() throws Exception {
            try{
                System.out.println("##Pre-commit");
                getSession().getTransaction().commit();
                System.out.println("##After-commit");
            }
            catch(Exception ex){
                /*getSession().getTransaction().rollback();
                HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
                 *
                 */
                System.out.println("##Catch-restart");
                restartTransaction();
                System.out.println("##Restarted-return");
                throw ex;
            }
        }
    
        public void restartTransaction(){
            getSession().getTransaction().rollback();
            HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
        }
    

    所以,当我调用commit时,commit方法中的catch(exception)应该截获异常,执行回滚并启动另一个事务,然后再次抛出exception。然后,方法delete应捕获ConstraintIOlationException,并添加相关实体的操作错误,并重定向到索引操作。但我得到的不是这个,而是例外:

    SEVERE: DELETE on table 'CATEGORIES' caused a violation of foreign key constraint 'FK8725ACED1BB98B18' for key (1).  The statement has been rolled back.
    24-Nov-2010 14:56:19 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
    SEVERE: Could not synchronize database state with session
    org.hibernate.exception.ConstraintViolationException: could not delete: [bytes.ewt.model.Categories#1]
            at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
            at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
            at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2541)
            at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2697)
            at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:74)
            at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:146)
            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
            at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
            at bytes.ewt.dao.EntitiesDAO.commit(EntitiesDAO.java:34)
            at bytes.ewt.struts.CategoriesAction.delete(CategoriesAction.java:120)
            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:597)
            at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:452)
            at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:291)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:254)
            at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
            at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:263)
            at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
            at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:133)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:207)
            at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:207)
            at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:94)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:267)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:142)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:166)
            at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:190)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
            at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
            at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
            at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:485)
            at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:395)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
            at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.struts2.dispatcher.ActionContextCleanUp.doFilter(ActionContextCleanUp.java:102)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at ua.org.bytes.ewt.web.filters.HibernateSessionRequestFilter.doFilter(HibernateSessionRequestFilter.java:35)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)
            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)
    ##Catch-restart
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    ##Restarted-return
            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:293)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
            at java.lang.Thread.run(Thread.java:619)
    Caused by: java.sql.SQLIntegrityConstraintViolationException: DELETE on table 'CATEGORIES' caused a violation of foreign key constraint 'FK8725ACED1BB98B18' for key (1).  The statement has been rolled back.
            at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
            at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
            at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
            at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
            at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
            at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
            at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
            at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
            at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeUpdate(Unknown Source)
            at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
            at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2520)
            ... 89 more
    Caused by: java.sql.SQLException: DELETE on table 'CATEGORIES' caused a violation of foreign key constraint 'FK8725ACED1BB98B18' for key (1).  The statement has been rolled back.
            at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
            at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
            ... 100 more
    enter code here
    

    请帮助我理解这种奇怪的行为(在我看来)。

    谢谢!

    2 回复  |  直到 13 年前
        1
  •  1
  •   darioo    15 年前

    其中有很多代码;我建议您执行以下操作之一:

    • cascade delete 如果你的设计允许你这样做
    • 在尝试删除之前,请使用Select检查子级是否存在;然后警告用户,不要执行删除操作。

    顺便说一下,使用字符串常量(如“operation-done”)进行状态检查对我来说似乎是个坏主意。你应该使用 static final string 像这样的东西。

    编辑 我想我知道你的问题在哪里了。

    以下部分:

     } catch(ConstraintViolationException ex){
            System.out.println("##Action-catch");
            //addActionError(getText("categories.in.use"));
            return "operation_done";
        } catch(Exception ex){
            System.out.println("##Action-all-catch: "+ex.getMessage() + ex.getClass() );
        }
    

    似乎有问题。当你发现一个例外的时候,它只是一个 Exception ConstraintViolationException ,您必须再次将其重新显示,使其在删除方法的“外部”可见。因此,该代码应该写为:

     } catch(ConstraintViolationException ex){
            System.out.println("##Action-catch");
            // addActionError(getText("categories.in.use"));
            // return "operation_done";
            throw ex;
        } catch(Exception ex){
            System.out.println("##Action-all-catch: "+ex.getMessage() + ex.getClass() );
            throw ex;
        }
    
        2
  •  0
  •   nmc Dihui Bao    13 年前

    我写的时候解决了 HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction(); 在EntitesDao类中提交之后