我遵循上面建议的结构(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>>
我有以下问题:
为什么控制器(userService.addUser(user)
中的com.bilitutor.cct.control.HomeController
)而不是DAO(sessionFactory.getCurrentSession().save(user);
)捕获异常,然后冒泡到控制器?
我知道我得到的是org.springframework.dao.DataIntegrityViolationException
,因为我正在使用@Repository
注释,这可能会进行异常翻译(如果我错了,请纠正我)。在这种情况下,当我捕获异常时,如何找到它的错误代码?
作为最佳做法,哪一层(DAO,服务或控制器)是捕获异常的最佳位置?
相关课程:
COntroller:
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);
}
}
DAO:
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);
}
}
}
答案 0 :(得分:1)
服务层发生异常。你可以在追踪中看到这个
at com.sun.proxy.$Proxy26.addUser(Unknown Source)
@Transactional
public void addUser(User user) {
userDAO.addUser(user);
}
如前所述,您的事务边界位于服务层,因此会发生异常。
我建议从服务方法中捕获/抛出正确的业务异常(已检查的异常)。服务方法包含您的业务逻辑,因此,如果出现任何问题,应通过服务方法抛出的异常将其正确地传达给外部世界。例如:WeakPasswordException,UserNameExistsException等
关于org.springframework.dao.DataIntegrityViolationException
试试
getCause()
查看已包装的异常
答案 1 :(得分:0)
1
我怀疑你把你的控制器处理程序方法作为事务边界,例如:
@RequestMapping
@Transactional
public String myHandler(..) {
...
}
只有在将更新同步到数据库后才能检测到重复行,如果您使用hibernate / jpa,这通常会在事务关闭时发生,因此您会看到它来自您的控制器
回想一下,@Transactional
通过jdk代理/方面编织工作。
3
答案取决于您的业务需求。当发生特定异常时,您需要做什么?
答案 2 :(得分:0)
1。 我相信异常是在控制器中捕获的,因为UserDAO.addUser()是事务边界。
2。 DataIntegrityViolationException扩展NestedRuntimeException,因此您可以使用getMessage,getMostSpecificCause,getRootCause
3。 在你的情况下,我应该在你的控制器中捕获异常。您希望在可以处理它们的层中捕获异常。到目前为止,例如,如果我正在编写DAO方法来获取对象列表。我可能会检查DAO中的异常并返回一个空列表并记录错误vs抛出异常。