Java通过SSH连接远程 MySQL 数据库

在本文中,我们学习了如何通过 SSH 会话连接到远程数据库。此外,我们还学习了本地端口转发,并应用它通过已建立的 SSH 会话连接到远程 MySQL 数据库。

安全外壳 (SSH) 允许我们安全地访问和管理远程系统,包括执行命令、传输文件和隧道服务。

我们可以通过 SSH 会话建立与远程 MySQL 数据库的连接。Java 中存在多个 SSH 客户端,其中最常见的一个是Java 安全通道 (JSch)。

在本教程中,我们将探讨如何通过 SSH 会话连接到远程服务器的本地主机上运行的 MySQL 数据库。

了解 SSH 端口转发
端口转发允许通过 SSH 连接将流量从本地端口引导到远程服务器上的端口,从而实现客户端系统和远程服务器之间的数据传输。

当防火墙或其他限制阻止直接连接到远程服务器的 IP 和端口时,这特别有用。

在我们的例子中,MySQL 服务器在 远程计算机的本地主机上运行,​​通常使用端口 3306。虽然从技术上讲可以直接连接到远程服务器的 IP 和 MySQL 端口,但出于安全目的,这样做通常受到限制。相反,我们可以使用 SSH 上的本地端口转发来建立与数据库的安全连接。

在本地端口转发中,我们在本地机器上分配一个可用端口,并将其与远程运行的MySQL服务器的端口绑定,以允许我们的程序和远程服务器之间的数据通信。

Maven 依赖项
首先,让我们将JSch和MySQL 连接器依赖项添加到pom.xml中:

<dependency>
    <groupId>com.github.mwiede</groupId>
    <artifactId>jsch</artifactId>
    <version>0.2.20</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>9.0.0</version>
</dependency>

JSch 依赖项提供了Session之类的类,这些类对于建立与远程服务器的 SSH 连接至关重要。此外,MySQL 连接器允许我们建立与正在运行的 MySQL 服务器的连接。

连接详细信息
此外,让我们定义与远程服务器的连接细节:

private static final String HOST = "HOST";
private static final String USER =
"USERNAME";
private static final String PRIVATE_KEY =
"PATH_TO_PRIVATEKEY";
private static final int PORT = 22;

在上面的代码中,我们定义了创建 SSH 会话所需的凭据。接下来,让我们定义与远程数据库的连接详细信息:

private static final String DATABASE_HOST = "localhost";
private static final int DATABASE_PORT = 3306;
private static final String DATABASE_USERNAME =
"DATABASE_USERNAME";
private static final String DATABASE_PASSWORD =
"DATABASE_PASSWORD";

MySQL 数据库运行在远程机器的localhost上,使用端口 3306。我们定义数据库用户名和密码来验证连接。

创建 SSH 会话
定义我们的连接详细信息后,让我们创建一个JSch实例来引导与远程服务器的连接:

JSch jsch = new JSch();
jsch.addIdentity(PRIVATE_KEY);

这里我们使用私钥来验证身份。但是,我们也可以使用基于密码的身份验证。

接下来,让我们创建一个新的 SSH 会话:

Session session = jsch.getSession(USER, HOST, PORT);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();

在上面的代码中,我们使用连接详细信息创建一个新的会话,并禁用密钥主机检查以简化操作。禁用主机密钥检查便于测试,但出于安全考虑,应避免在生产中这样做。

最后,我们调用Session对象上的connect()方法来打开一个新的 SSH 会话。

通过端口转发连接MySQL
接下来,让我们使用 SSH 端口转发来隧道化 MySQL 端口:

int port = session.setPortForwardingL(0, DATABASE_HOST, DATABASE_PORT);

在上面的代码中,我们调用Session对象上的setPortForwardingL()方法来设置本地端口转发。通过传递0作为本地端口,程序会动态选择可用的本地端口,将流量转发到远程 MySQL 服务器的端口 3306。

端口转发(隧道)允许发送到本地端口的流量通过 SSH 连接转发到远程计算机上的 MySQL 服务器。

此外,让我们使用转发端口连接到 MySQL 服务器:

String databaseUrl = "jdbc:mysql://" + DATABASE_HOST + ":" + port + "/baeldung";
Connection connection = DriverManager.getConnection(databaseUrl, DATABASE_USERNAME, DATABASE_PASSWORD);

在上面的代码中,我们使用 JDBC Connection类建立与数据库的连接。在我们的数据库 URL 中,我们使用转发的本地端口,而不是远程 MySQL 服务器的默认端口 (3306)。

此外,让我们验证一下连接是否存在:

assertNotNull(connection);

在上面的代码中,我们断言与数据库的连接不为空。

简单查询
另外,让我们对已建立的连接执行一些数据库操作。首先,让我们创建一个表:

String createTableSQL = "CREATE TABLE test_table (id INT, data VARCHAR(255))";
try (Statement statement = connection.createStatement()) {
    statement.execute(createTableSQL);
}

这里我们在baeldung数据库中创建一个test_table。接下来,我们在创建的表中插入一条记录:

String insertDataSQL = "INSERT INTO test_table (id, data) VALUES (1, 'test data')";
try (Statement statement = connection.createStatement()) {
    statement.execute(insertDataSQL);
}

最后,让我们断言创建的表存在于数据库中:

try (Statement statement = connection.createStatement()) {
    ResultSet resultSet = statement.executeQuery("SHOW TABLES LIKE 'test_table'");
    return resultSet.next();


在上面的代码中,我们验证创建的表是否存在于数据库中。

关闭连接
本质上,我们需要在操作后关闭SSH会话和数据库连接:

session.disconnect();
connection.close();

在上面的代码中,我们分别调用Session和Connection对象的disconnect()和close()方法来释放资源。它还可以防止潜在的内存泄漏。