Struts 2 + Hibernate:无法捕获ConstraintViolationException

时间:2010-11-24 13:18:43

标签: hibernate struts2

我正在使用Struts 2.2.1和Hibernate3编写Web应用程序。当我尝试删除与其他实体具有一对多关系的实体时,我遇到了问题。我想实现这样的场景:1)开放会话 - > 2)尝试删除实体3)提交4)Catch ConstraintViolationException,然后回滚并向用户显示消息,在另一个表中有相关​​项。但是我无法捕获ConstraintViolationException!这是我的hibernate配置:

<?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>

我在网络过滤器中的会话管理:

    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 action()删除Category时,我添加了system.out来调试puroses:

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";
}

和mgr的提交代码:

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)应该拦截异常,执行回滚并启动另一个事务,然后再次抛出异常。然后方法delete应捕获ConstraintViolationException并添加有关相关实体的操作错误并重定向到索引操作。但是,除此之外,我得到例外:

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 个答案:

答案 0 :(得分:1)

那里有很多代码;我建议做以下其中一项:

  • 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() );
    }

似乎有问题。当您捕获异常时,只需ExceptionConstraintViolationException,您必须再次重新抛出它才能使其在“外部”显示为您的删除方法。因此,该代码应写为:

 } 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;
    }

答案 1 :(得分:0)

在EntitesDAO类

中提交后写HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();时解决了