1、概览 {#1概览}
Secure Shell(SSH)允许我们安全地访问和管理远程系统,包括执行命令、传输文件和隧道服务。
我们可以通过 SSH 会话建立与远程 MySQL 数据库的连接。Java 有多个 SSH 客户端,其中最常见的是 Java Secure Channel(JSch)。
本文将带你了解如何通过 SSH 会话连接到运行在远程服务器上的 MySQL 数据库。
2、了解 SSH 端口转发 {#2了解-ssh-端口转发}
端口转发允许通过在 SSH 连接上将流量从本地端口重定向到远程服务器上的端口,从而实现客户系统和远程服务器之间的数据传输。
当防火墙或其他限制阻止直接连接远程服务器的 IP 和端口时,这一点尤其有用。
在本例中,MySQL 服务器运行在远程服务器的 localhost 上,通常使用 3306 端口。虽然从技术上讲,可以直接连接到远程服务器的 IP 和 MySQL 端口,但出于安全考虑,这通常会受到限制(3306 端口未开放)。相反,我们可以通过 SSH 使用本地端口转发来建立与数据库的安全连接。
在本地端口转发中,我们在本地机器上分配一个可用端口,并将其与远程运行的 MySQL 服务器端口绑定,以允许我们的程序与远程服务器之间进行数据通信。
3、Maven 依赖 {#3maven-依赖}
首先,在 pom.xml 中添加 JSch 和 MySQL 驱动依赖:
<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 服务器建立连接。
4、连接配置 {#4连接配置}
定义与远程服务器的连接配置:
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 端口。我们定义了数据库用户名和密码,用于验证连接。
5、创建 SSH 会话 {#5创建-ssh-会话}
连接信息定义后,让我们创建一个 JSch 实例来启动与远程服务器的连接:
JSch jsch = new JSch();
jsch.addIdentity(PRIVATE_KEY);
如上,我们使用私钥来验证身份。当然,也可以使用基于密码的身份认证。
接着,创建一个新的 SSH 会话(Session):
Session session = jsch.getSession(USER, HOST, PORT);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
代码如上,我们创建了一个新会话,为了便于测试,我们禁用了 Host Key 检查,但在生产环境中,出于安全考虑应避免这样做。
最后,调用 Session
对象上的 connect()
方法来打开一个新的 SSH 会话。
6、通过端口转发连接 MySQL {#6通过端口转发连接-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
)。
此外,还要验证连接是否有效,断言与数据库的连接(connection
)不是 null
。
assertNotNull(connection);
7、简单的查询 {#7简单的查询}
现在,让我们在已建立的连接上执行一些数据库操作。首先,创建一个表:
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();
}
8、关闭连接 {#8关闭连接}
一样的,操作完毕后需要关闭 SSH 会话和数据库连接:
session.disconnect();
connection.close();
如上,在 Session
和 Connection
对象上分别调用了 disconnect()
和 close()
方法,以释放资源,防止潜在的内存泄漏。
9、总结 {#9总结}
本文介绍了 SSH 和 SSH 端口转发,以及如何使用 Java 通过 SSH 连接远程 MySQL 数据库。
Ref:https://www.baeldung.com/java-ssh-remote-mysql-db-connection