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
相关产品推荐
相关产品推荐

