【问题标题】:What are the best practices to handle exception at Controller, Service and DAO Layer simultaneously in Spring & Hibernate在 Spring & Hibernate 中同时处理 Controller、Service 和 DAO 层异常的最佳实践是什么
【发布时间】:2015-04-19 14:43:04
【问题描述】:

我正在开发 Spring 3.2 和 Hibernate 3.6,任何人都可以解释如何在 Sping MVC 和 Hibernate 中处理异常...我只是分享示例代码。

控制器层

public Integer saveEployee(HttpServletRequest req, HttpServletResponse res){
    Employee empObj = new Employee();
    empObj.setName(req.getParameter("empName"));
    ......................
    ......................
    Integer empId = materService.saveEmployee(empObj);
    return empId; 
}

服务层

public Integer saveEmployee(Employee empObj){
    return masterDao.saveEmployee(empObj);
}

DAO 层

public Integer saveEmployee(Employee empObj){
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    Integer empId = session.save(empObj);
    tx.commit();
    session.close();
    return empId;
}
  1. 现在假设在保存 empObj 时在 DAO 层发生了任何异常,例如 d/b 关闭或连接失败或发生任何其他类型的休眠异常,例如 ConstraintViolationExceptionIntegrityConstraintViolationException 等。

  2. 如果有可能在控制器层处理 NullPointerException 或任何用户定义的异常等 java 异常。

那么最佳实践是什么?或者如何在Controller、Service和DAO层同时处理异常。

【问题讨论】:

  • 您可以使用@ControllerAdvice 处理应用程序中任何层抛出的异常。我的意思是,如果在 DAO 或服务层发生任何异常,它将被抛出到 Controller。您的 ControllerAdvice 将处理来自每个控制器的异常。可以参考这篇文章spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
  • @thoitbk 是这项工作,即使我在 DAO 层发生任何类型的休眠异常,假设 ConstraintViolationException ?
  • 当然。您可以根据需要处理任何类型的异常。只需在 ControllerAdvice 类中创建每种方法来处理每种类型的异常。这些方法用@ExceptionHandler(value={ConstraintViolationException.class, IntegrityConstraintViolationException.class,...})注释

标签: java spring hibernate exception


【解决方案1】:

根据我在新项目中的经验,

  1. 您不应在 DAO 层处理异常。 原因:通常我们在服务层放置@Transactional注解。因此我们需要在服务层回滚事务。如果您在 DAO 处理异常,则它不会回滚。 按照下面的链接了解为什么我们应该将@Transaction 放在服务层。
    Where should "@Transactional" be place Service Layer or DAO
  2. 您不应在服务层处理异常。 原因:由于服务层执行多个DAO进行DB操作,如果任何DAO失败,我们需要回滚事务。如果我们在服务中处理异常,那么我们可能不会回滚事务。 回滚事务有手动方法,但不推荐。 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

所以在控制器层处理事务。

【讨论】:

    【解决方案2】:

    您不会同时处理应用程序所有级别的异常;您必须考虑它们的上下文含义以及适合您的应用程序的策略。有些错误应该被忽略,有些应该被包装,有些应该允许直接引发。

    spring-mvc 应用程序中处理异常的一种方法是在适当的情况下使用您自己的底层库来包装致命错误,并以它们被抛出的级别命名,例如ServiceExceptionRepositoryException。然后,@ControllerAdvice-annotated 类可以使用 @ErrorHandler-annotated 方法处理这些错误并返回 5XX http 错误。

    常见的应用程序错误,例如由于不正确的id 而找不到实体可能会导致自定义异常,例如NotFoundException 被提升并随后被您的 @ControllerAdvice-annotated 类捕获。

    这种技术的优点是您在不同应用程序层中的错误处理代码更少,并且可以集中将异常转换为响应。

    @ControllerAdvice-annotated 类的示例:

    @ControllerAdvice
    public class ErrorHandler extends ResponseEntityExceptionHandler {
        @ExceptionHandler({NotFoundException.class})
        protected ResponseEntity<Object> handleNotFound(RuntimeException e, WebRequest request) {
            return handleExceptionInternal(e, e.getMessage(),
                    null,
                    HttpStatus.NOT_FOUND, request);
        }
    
        @ExceptionHandler({ServiceException.class, RepositoryException.class})
        protected ResponseEntity<Object> handleInternalError(RuntimeException e, WebRequest request) {
            return handleExceptionInternal(e, e.getMessage(),
                    null,
                    HttpStatus.INTERNAL_SERVER_ERROR, request);
        }
    }
    

    【讨论】:

    • 如果我想在异常发生时执行一些逻辑,比如将状态更改为失败。
    【解决方案3】:

    您应该使您的服务具有事务性并在控制器层处理异常:您可以选择基于控制器的异常处理(使用@ExceptionHandler)或全局异常处理(使用@ControllerAdvice 类)。 显示一些东西可能是实用的,例如出现异常时向用户显示错误页面。

    您可以在 Spring MVC here 中找到有用的异常处理示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      相关资源
      最近更新 更多