我正在尝试改善我在Spring MVC应用程序中处理来自DAO /服务层的异常的方式。我在下面使用的方法效果很好,不会导致500错误:
控制器代码
response.numChildren()
服务代码
4
DAO代码
@RequestMapping(value = {"/delete-{id}-strengthUnit"}, method = RequestMethod.GET)
public String deleteStrengthUnit(@PathVariable String id)
{
StrengthUnit strengthUnit = strengthUnitService.findById(Integer.parseInt(id));
try
{
strengthUnitService.delete(strengthUnit);
session.setAttribute("successMessage", "Successfully deleted strength unit \"" + strengthUnit.getName() + "\"!");
}
catch (Exception ex)
{
session.setAttribute("errorMessage", "Strength unit \"" + strengthUnit.getName() + "\" is in use and cannot be deleted!");
}
return "redirect:/strengthUnits/list";
}
主DAO代码(所有DAO都扩展了此抽象DAO类)
@Override
public void delete(StrengthUnit strengthUnit) throws ConstraintViolationException
{
dao.delete(strengthUnit);
}
此代码链正确地拦截ConstraintViolationException(由DAO层抛出并由服务层转发给控制器),并在会话对象中设置一个变量,并在下一页中向用户显示一条漂亮的消息。所有这些都可以像现在一样完美地运行。
我正在尝试改善我的服务层,以便它可以执行与DAO层进行交互所导致的所有异常捕获和日志记录职责。我正在尝试做出一个非常简单的更改,并且我无法终生理解为什么这样做时无法捕获ConstraintViolationException:
控制器代码
@Override
public void delete(StrengthUnit strengthUnit) throws ConstraintViolationException
{
super.delete(strengthUnit);
}
服务代码
public void delete(T entity)
{
getSession().delete(entity);
}
DAO代码完全不变。通过这些简单的更改,控制器应该会收到我的自定义异常,但不会。执行不会进入服务层中的catch块,即使在更改之前事情做得很好,也没有更改DAO层。这是当代码完全跳过catch块时得到的异常:
@RequestMapping(value = {"/delete-{id}-strengthUnit"}, method = RequestMethod.GET)
public String deleteStrengthUnit(@PathVariable String id)
{
StrengthUnit strengthUnit = strengthUnitService.findById(Integer.parseInt(id));
try
{
strengthUnitService.delete(strengthUnit);
session.setAttribute("successMessage", "Successfully deleted strength unit \"" + strengthUnit.getName() + "\"!");
}
catch (EntityInUseException ex)
{
session.setAttribute("errorMessage", "Strength unit \"" + strengthUnit.getName() + "\" is in use and cannot be deleted!");
}
return "redirect:/strengthUnits/list";
}
我查看了另一个实体的删除操作(我尚未更改的一个删除操作),并且该异常实际上是DataIntegrityViolationException。即使将DAO设置为引发该异常,我也无法让我的服务层捕获它。即使直到我立即收到500错误和上面的stacktrace,catch块也永远不会到达,并且在日志中打印成功消息。
这对任何人有意义吗?
谢谢!
答案 0 :(得分:2)
答案在问题中。读取堆栈跟踪。我不是引发异常的delete()方法。因为delete()仅在于在持久性上下文中标记要删除的实体。实际的删除发生在刷新时,即Hibernate在提交之前实际执行delete查询时。并且由于该服务是事务性的,因此提交会在包裹实际服务实例的事务性代理中发生:
冲洗:
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3278)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2474)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
在Hibernate提交事务时调用:
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98)
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:609)
因为Spring TransactionManager延迟到Hibernate提交
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:532)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
在服务周围的代理内部
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy107.delete(Unknown Source)