9

在此处输入图像描述

我遵循上面建议的结构(http://viralpatel.net/blogs/spring3-mvc-hibernate-maven-tutorial-eclipse-example/)。我尝试添加重复条目,导致以下异常:

SEVERE: Servlet.service() for servlet [appServlet] in context with path [/cct] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Duplicate entry 'a@b.com' for key 'PRIMARY'; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Duplicate entry 'a@b.com' for key 'PRIMARY'] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'a@b.com' for key 'PRIMARY'
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
    at << removed for readability>> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy26.addUser(Unknown Source)
    at com.bilitutor.cct.control.HomeController.signup(HomeController.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    << removed for readability>> 

我有以下问题:

  1. 为什么异常被控制器(userService.addUser(user)in com.bilitutor.cct.control.HomeController)而不是DAO(sessionFactory.getCurrentSession().save(user);)捕获,然后冒泡到控制器?

  2. 我知道我得到了一个org.springframework.dao.DataIntegrityViolationException,因为我正在使用@Repository注释,它可能会进行异常翻译(如果我错了,请纠正我)。在那种情况下,当我捕捉到异常时,如何找到它的错误代码?

  3. 作为最佳实践,在哪个层(DAO、服务或控制器)是捕获异常的最佳位置?

相关课程:

控制器 :

package com.bilitutor.cct.control;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.web.bind.annotation.ModelAttribute;

import com.bilitutor.cct.bean.*;
import com.bilitutor.cct.service.*;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

    @Autowired
    UserService userService;

    @ModelAttribute("user")
    public User getUserObect() {
      return new User();
    }

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    /**
     * Landing page. Just return the login.jsp
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {
        logger.info("home() called");
        return "login";
    }

    /**
     * Login. Either forward to the user's homepage or return back the error
     */
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(Model model) {
        logger.info("login() called");
        return "login";
    }

    /**
     * New User signup. If user already exists, send back the error, or send an email and forward to the email validation page
     */
    @RequestMapping(value = "/signup", method = RequestMethod.POST)
    public String signup(@ModelAttribute("user")User user, BindingResult result) {
        logger.info("signup() : email="+user.getEmail()+" pass="+user.getPassword()+" accessCode="+user.getAccessCode());
        userService.addUser(user);
        return "login";
    }

}

服务:

package com.bilitutor.cct.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.bilitutor.cct.dao.UserDAO;
import com.bilitutor.cct.bean.User;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDAO;

    @Transactional
    public void addUser(User user) {
        userDAO.addUser(user);
    }

    @Transactional
    public void removeUser(String email) {
        userDAO.removeUser(email);
    }

}

道:

package com.bilitutor.cct.dao;

import com.bilitutor.cct.bean.User;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UserDAOImpl implements UserDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void addUser(User user) {
        sessionFactory.getCurrentSession().save(user);
    }

    public void removeUser(String email) {
        User user = (User) sessionFactory.getCurrentSession().load(User.class, email);
        if (user!=null) {
            sessionFactory.getCurrentSession().delete(user);
        }

    }
}
4

3 回答 3

1

Exception is occuring at service layer. You can see this in trace

at com.sun.proxy.$Proxy26.addUser(Unknown Source)

@Transactional
public void addUser(User user) {
    userDAO.addUser(user);
}

As previous answer says your transaction boundary is at service layer, so exception occurs there.

I would recommend to catch/throw proper business exceptions(checked exceptions) from service methods. Service methods incorporate your business logic so , if anything goes wrong it should be properly communicated to outer world through the exceptions that service methods throw. For eg : WeakPasswordException, UserNameExistsException etc

Regarding org.springframework.dao.DataIntegrityViolationException try calling getCause() to see the wrapped exception

于 2013-08-07T05:21:15.687 回答
0

1.

我怀疑您将控制器处理程序方法作为事务边界,例如:

@RequestMapping
@Transactional
public String myHandler(..) {
  ...
}

只有在更新同步到数据库后才能检测到重复行,如果您使用 hibernate/jpa,这通常发生在事务关闭时,因此您会看到它好像来自您的控制器

回想一下@Transactionaljdk 代理/方面编织的工作原理。

3.

答案取决于您的业务需求。当发生特定异常时,您需要发生什么?

于 2013-08-07T04:29:50.237 回答
0

1. 我相信异常在控制器中被捕获,因为 UserDAO.addUser() 是事务边界。

2. DataIntegrityViolationException扩展了 NestedRuntimeException,因此您可以使用 getMessage、getMostSpecificCause、getRootCause

3.在你上面的例子中,你应该在你的控制器中捕获异常。您想在可以处理异常的层捕获异常。到目前为止,如果我正在编写一个 DAO 方法来获取对象列表。我可能会检查 DAO 中的异常并返回一个空列表并记录错误与抛出异常。

于 2013-08-07T05:24:12.557 回答