Java 在SpringMVC应用程序中向数据库添加重复用户名时如何处理异常

Java 在SpringMVC应用程序中向数据库添加重复用户名时如何处理异常,java,mysql,spring,spring-mvc,Java,Mysql,Spring,Spring Mvc,我正在构建SpringMVC应用程序。我想建议添加重复的(用户名是主键)条目,并通知您选择另一个用户名 我正在研究注册用户选项。在我使用已经存在的用户名输入用户之前,一切正常。这是经过深思熟虑的,因为用户名列是我数据库中的主键 我正在寻找处理此问题的选项,以便: 这是我的SQL表 create table users( username varchar(50) not null primary key, password varchar(50) not null); 这是我的存储库:

我正在构建SpringMVC应用程序。我想建议添加重复的(用户名是主键)条目,并通知您选择另一个用户名

我正在研究注册用户选项。在我使用已经存在的用户名输入用户之前,一切正常。这是经过深思熟虑的,因为用户名列是我数据库中的主键

我正在寻找处理此问题的选项,以便:

这是我的SQL表

 create table users(
  username varchar(50) not null primary key,
  password varchar(50) not null);
这是我的存储库:

@Repository

class UserRepositoryImpl implements UserRepository{

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void addUser(User user) throws MySQLIntegrityConstraintViolationException {
        /*language=SQL*/
        String SQL_ADD_USER= "INSERT INTO users VALUES (?,?)";

        String username  = user.getUsername();
        String password  = user.getPassword();
        jdbcTemplate.update(SQL_ADD_USER, username, password);

    }
}
这是我的控制器类的一部分:

@RequestMapping(value="/register", method = RequestMethod.GET)
public String registerPage(@ModelAttribute("user") User user){return "register";}

@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegisterUser(@ModelAttribute("user") User user, BindingResult result){

    try {
        userRepository.addUser(user);
    } catch (com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException e) {

        //some line of code that would add information to the view that user with given username already exists.
    }


    return "redirect:/login";
}
正如您所看到的,我试图处理在添加重复条目期间发生的异常。这就是为什么我把这个子句
抛出MySQLIntegrityConstraintViolationException
放在public void addUser(User User)中。在下一步中,我想在
publicstringprocessregisteruser
方法中处理此异常,以便在视图中通知用户给定的用户名已被占用。嗯,它不起作用。我无法处理
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException
,在添加重复错误而不是视图中的警告时,我得到:

 HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'

type Exception report

message Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'

description The server encountered an internal error that prevented it from fulfilling this request.

exception

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
        org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
        org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
        org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)

如果您需要任何详细信息,请评论

您只处理MySQLIntegrityConstraintViolationException而不是其他异常:NestedServletException和DuplicateKeyException,因此您将获得stacktrace,而您的try/catch不起作用

顺便说一句,为什么不简单地创建一个额外的方法来检查用户名是否已经存在,如果是,则显示错误消息,否则添加用户

class UserRepositoryImpl implements UserRepository{
    //.....
    public int isUsernameExist(String username){
        String sql = "SELECT COUNT(*) FROM users WHERE username=?";
        return jdbcTemplate.queryForObject(sql, new Object[] { username }, String.class);
    }
    //....
}

@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegisterUser(@ModelAttribute("user") User user, BindingResult result){
    int status = userRepository.isUserExist(user.getUsername());
    if(status==1){
        //Username exist... redirect and display error msg.
    } else {
        userRepository.addUser(user);
    }
    //.....
}

您正在使用spring jdbcTemplate进行db连接,它有自己的异常层次结构,因此您可以尝试捕获spring异常org.springframework.dao.DuplicateKeyException

try
Query.uniqueResult()
,如本节或中所述

实体类

@NamedQuery(
name = "getAccountByAccountId",
query = "from Account where username = :username")
@Entity
@Table(name = "account")
public class Account {

我将通过捕获异常(以避免竞争条件)来解决这个问题,然后向BindingResult添加一个错误,以便能够在(JSP/Thymeleaf)视图模板中显示错误


@控制器
公共类用户控制器{
专用最终用户服务用户服务;
公共用户控制器(用户服务用户服务){
this.userService=userService;
}
/**
*如果没有错误,则添加新用户并重定向到用户,否则返回添加用户模板。
*/
@后期映射(“/admin/add\u user”)
公共字符串姿势器(模型模型,@Valid UserForm UserForm,BindingResult){
if(result.hasErrors()){
//可能在此处向模型添加属性。出现错误时不要重定向。
返回“添加用户”;
}
试一试{
userService.createUser(
User.withUsername(userForm.getUsername()).password(userForm.getPassword()).roles(“ADMIN”).build());
}捕获(最终副本e){
result.rejectValue(“用户名”、“用户名使用”、“用户名已在使用”);
返回姿势(模型、用户表单、结果);
}
//如果没有错误,则在post后重定向
返回“重定向:/admin/users”;
}
}
用户表单包含标准JSR303验证注释

@数据
公共类用户窗体{
@长度(最小值=1,最大值=50)
@空空如也
私有字符串用户名;
@空空如也
私有字符串密码;
}

您有用于显示注册表的jsp页面吗?我有。它很好用。嗯,我还没有添加任何字段来显示注册表中的错误消息。但这并不重要。我在try-catch块中添加了一些redistration来进行测试,我可以告诉您我是如何让它为我工作的——但在我的例子中,我使用了Hibernate验证来进行测试,没有例外。你想听听我的例子还是想坚持例外部分?@lenach87当然。我对专业程序员如何解决这个问题感兴趣。我愿意接受你的回答。我很高兴得到任何帮助和建议。很抱歉让您困惑,我反复检查了一下,我所做的不是检查唯一性,而是其他事情(有效的电子邮件模式,密码中的字母数)-但是对于唯一性,这样的事情不起作用。再次为混淆感到抱歉。嗯,检查用户是否存在并添加它似乎没有问题。但这是一个有效的解决方案吗?假设我们想在fb dtabse中注册用户,因为fb dtabse有这么多用户。我对专业程序员如何解决这个问题感兴趣。必须有一些推荐的模式来解决这个问题。在数百万事务的情况下,可能会有开销问题,因为有2个数据库调用。顺便说一句,如果您想处理带有异常的重复用户名错误,只需使用exception而不是MySQLIntegrityConstraintViolationException,这样它就可以处理所有类型的异常。但无论如何。通过处理异常来解决我的问题是一种好的做法吗?我想知道一些专业开发人员会如何解决这个问题。好吧,除非你知道会抛出什么异常。这取决于开发人员如何解决此类问题以及问题的性质。但如果谈到好处,在不仅出现重复的主键,而且数据库服务器关闭或数据库中出现内部错误的情况下,使用exception会非常有帮助。在添加用户之前检查用户是否存在会导致竞争条件。如果两个用户希望在同一用户上创建同一用户,则一个请求将失败,并出现您试图避免的异常。您是对的,我只是将MySQLIntegrityConstraintViolationException与DuplicateKeyException交换。我是初学者,我想知道专业开发人员如何处理我的问题。我的意思是不允许在注册期间在web应用程序中再次使用相同的用户名、电子邮件。
@NamedQuery(
name = "getAccountByAccountId",
query = "from Account where username = :username")
@Entity
@Table(name = "account")
public class Account {