Java SSH隧道连VPN数据库查询结果为空,需验证评论数一致性
解决SSH隧道连接数据库后查询结果为空的问题
我看你遇到了通过SSH隧道连接数据库后,控制台显示SSH已连接但数据库查询结果为空的问题,咱们一步步来排查和解决:
核心问题分析
你的代码里有几个关键配置错误,导致数据库连接实际上没正确建立,所以查询返回空结果:
1. 数据库连接地址配置错误
在connectToDataBase方法中,你把localSSHUrl设置成了远程数据库的IP,但SSH端口转发的作用是把本地端口映射到远程数据库端口,所以应该连接localhost(本地转发端口),而不是直接连远程数据库IP。另外你注释掉了setPortNumber(localPort),必须指定本地转发的端口(8740)才能正确连接。
2. MySQL驱动类适配问题
如果你的MySQL版本是8.0及以上,com.mysql.jdbc.Driver已经被废弃,应该使用com.mysql.cj.jdbc.Driver,而且JDBC 4.0+不需要手动调用Class.forName(...).newInstance()来加载驱动。
3. 资源泄漏与ResultSet遍历时机问题
你的代码中没有正确关闭Statement和ResultSet,而且在executeMyQuery返回ResultSet后,后续方法在finally块中关闭连接,虽然遍历是在关闭前,但如果ResultSet依赖连接存活(默认行为),一旦连接关闭ResultSet就无法访问。这不是当前查询为空的直接原因,但必须修复避免后续问题。
修正后的关键代码
修正connectSSH方法
public static void connectSSH() throws SQLException { String sshHost = "my ssh host"; String sshuser = "my ssh user"; String SshKeyFilepath = "/Users/mac/.ssh/id_rsa"; int localPort = 8740; String remoteHost = "ip db"; int remotePort = 3306; // MySQL 8+使用新版驱动类 String driverName = "com.mysql.cj.jdbc.Driver"; try { java.util.Properties config = new java.util.Properties(); JSch jsch = new JSch(); session = jsch.getSession(sshuser, sshHost, 22); jsch.addIdentity(SshKeyFilepath); config.put("StrictHostKeyChecking", "no"); config.put("ConnectionAttempts", "3"); session.setConfig(config); session.connect(); System.out.println("SSH Connected"); // JDBC 4.0+可省略驱动注册,但保留也没问题 Class.forName(driverName); int assigned_port = session.setPortForwardingL(localPort, remoteHost, remotePort); System.out.println("localhost:" + assigned_port + " -> " + remoteHost + ":" + remotePort); System.out.println("Port Forwarded"); } catch (Exception e) { e.printStackTrace(); // 抛出异常让上层处理,避免SSH连接失败后继续执行数据库操作 throw new SQLException("Failed to establish SSH connection", e); } }
修正connectToDataBase方法
public static void connectToDataBase(String dataBaseName) throws SQLException { String dbuserName = "username db"; String dbpassword = "pass db"; int localPort = 8740; // SSH转发后,连接本地localhost,而非远程数据库IP String localSSHUrl = "localhost"; try { MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setServerName(localSSHUrl); // 必须指定本地转发的端口 dataSource.setPortNumber(localPort); dataSource.setUser(dbuserName); dataSource.setAllowMultiQueries(true); dataSource.setPassword(dbpassword); dataSource.setDatabaseName(dataBaseName); // MySQL 8+必须配置时区,否则可能连接失败 dataSource.setServerTimezone("UTC"); connection = dataSource.getConnection(); System.out.print("Connection to server successful!:" + connection + "\n\n"); } catch (Exception e) { e.printStackTrace(); throw new SQLException("Failed to connect to database", e); } }
修复executeMyQuery的资源管理
public static List<Map<String, Object>> executeMyQuery(String query, String dataBaseName) { List<Map<String, Object>> resultList = new ArrayList<>(); try (Connection conn = getConnection(dataBaseName); Statement stmt = conn.createStatement(); ResultSet resultSet = stmt.executeQuery(query)) { ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); while (resultSet.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnName(i), resultSet.getObject(i)); } resultList.add(row); } System.out.println("Database query executed successfully, returned " + resultList.size() + " rows"); return resultList; } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("Query execution failed", e); } finally { closeConnections(); } } // 重构获取连接的方法,避免重复代码 private static Connection getConnection(String dataBaseName) throws SQLException { connectSSH(); connectToDataBase(dataBaseName); return connection; }
修正getAllDBNames方法(使用新的查询方法)
public static List<String> getAllDBNames() { List<Map<String, Object>> queryResult = executeMyQuery("show databases", "DB1"); List<String> organisationDbNames = new ArrayList<>(); for (Map<String, Object> row : queryResult) { organisationDbNames.add(row.get("Database").toString()); } return organisationDbNames; }
测试建议
- 先确认SSH隧道是否真的生效:用本地MySQL客户端连接
localhost:8740,输入数据库用户名和密码,看是否能正常访问数据库。如果客户端也连不上,说明SSH端口转发有问题,检查SSH主机、用户名、密钥路径是否正确。 - 运行修正后的代码,查看控制台输出的连接信息,确认数据库连接成功。
- 测试
getAllDBNames方法,看是否能返回数据库列表。
内容的提问来源于stack exchange,提问作者Prasetyo Budi
相关产品推荐
相关产品推荐

