You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDBC连接数过多问题解决及用户登录验证失败排查

问题描述
  • 用户信息可存入数据库,但直接登录无法完成;重启应用后,使用数据库中已存在的账号登录,系统提示Invalid username or password
  • 存在too many connections数据库连接错误

相关代码

DBConnector类中的登录方法

public void loginUsersIntoStore(User user) throws SQLException{
    connection = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
    String sql = "SELECT id FROM users WHERE username=? AND password=?";
    pStatement = connection.prepareStatement(sql);
    pStatement.setString(1, user.getUsername());
    pStatement.setString(2, user.getPassword());

    ResultSet resultSet = pStatement.executeQuery();
    boolean found = false;

    if(resultSet.next()) {
        int id = resultSet.getInt("ID");
        if (id != 0) {
            found = true;
        }
    }

    if(found){
        loginUsersIntoStore(user);
        pStatement.executeQuery();
        pStatement.close();
        connection.close();
    }
    if(!found){
        System.out.println("Invalid login credentials");
    }
}

Main中的登录调用逻辑

private static void login(UserManager userManager, Scanner input) throws SQLException {
    System.out.print("Enter username: ");
    String userName = input.next();

    System.out.print("Enter password: ");
    String password = input.next();

    User user = new User(userName, password);
    boolean isAuthenticated = userManager.authenticate(user);

    if (isAuthenticated) {
        DBConnector.getInstance().loginUsersIntoStore(user);
        System.out.println("Login was successful!");

    } else {
        System.out.println("Invalid username or passwordl!");
    }
}

问题分析与修复方案

1. 登录逻辑的核心问题

  • 无限递归:当found为true时,代码会再次调用loginUsersIntoStore(user),导致无限循环,永远无法执行到连接关闭和登录成功的逻辑,直接引发程序卡死或栈溢出。
  • 资源未完全释放:查询生成的ResultSet未关闭,持续占用数据库资源。
  • 列名大小写不兼容:resultSet.getInt("ID")中的列名如果数据库实际存储为小写id,会抛出异常导致found始终为false,重启后登录失败。

修复后的DBConnector登录方法:

public boolean loginUsersIntoStore(User user) throws SQLException{
    // 使用try-with-resources自动关闭Connection、PreparedStatement、ResultSet
    try (Connection connection = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
         PreparedStatement pStatement = connection.prepareStatement("SELECT id FROM users WHERE username=? AND password=?")) {

        pStatement.setString(1, user.getUsername());
        pStatement.setString(2, user.getPassword());

        try (ResultSet resultSet = pStatement.executeQuery()) {
            // 直接判断结果集是否有数据即可,无需额外检查id值
            return resultSet.next();
        }
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}

2. 简化Main中的登录调用逻辑

原代码存在重复验证的冗余,直接调用DBConnector的验证方法即可:

private static void login(UserManager userManager, Scanner input) throws SQLException {
    System.out.print("Enter username: ");
    String userName = input.next();

    System.out.print("Enter password: ");
    String password = input.next();

    User user = new User(userName, password);
    boolean isAuthenticated = DBConnector.getInstance().loginUsersIntoStore(user);

    if (isAuthenticated) {
        System.out.println("Login was successful!");
    } else {
        System.out.println("Invalid username or password!");
    }
}

3. 解决too many connections错误

  • 改用连接池:放弃每次请求新建连接的方式,使用HikariCP等JDBC连接池复用连接,控制连接总数。
  • 强制资源自动释放:所有数据库操作的Connection、PreparedStatement、ResultSet都使用try-with-resources语法,确保资源自动回收,避免连接泄漏。
  • 排查全模块连接泄漏:检查商品模块等其他数据库操作代码,确保所有连接都被正确关闭。

内容的提问来源于stack exchange,提问作者Raduci

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:27:41