如何通过SSH从Java应用程序连接到远程MySQL数据库?小代码示例对我很有帮助,我很感激。
答案 0 :(得分:39)
我的理解是你想要访问在远程机器上运行的mysql服务器并通过SSH隧道监听端口3306。
要使用命令行ssh client从本地计算机上的端口1234到远程计算机上的端口3306创建此类隧道,您可以从本地计算机中键入以下命令:
ssh -L 1234:localhost:3306 mysql.server.remote
要从Java执行相同的操作,您可以使用JSch,这是SSH2的Java实现。从其网站:
JSch允许您连接到sshd服务器并使用端口转发,X11转发,文件传输等,您可以将其功能集成到您自己的Java程序中。 JSch根据BSD风格许可证授权。
例如,请查看PortForwardingL.java
。连接会话后,使用jdbc:mysql://localhost:1234/[database]
之类的连接URL创建与MySQL的JDBC连接。
答案 1 :(得分:15)
我的详细代码如下:
package mypackage;
import java.sql.*;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class UpdateMySqlDatabase {
static int lport;
static String rhost;
static int rport;
public static void go(){
String user = "ripon";
String password = "wasim";
String host = "myhost.ripon.wasim";
int port=22;
try
{
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
lport = 4321;
rhost = "localhost";
rport = 3306;
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
System.out.println("Establishing Connection...");
session.connect();
int assinged_port=session.setPortForwardingL(lport, rhost, rport);
System.out.println("localhost:"+assinged_port+" -> "+rhost+":"+rport);
}
catch(Exception e){System.err.print(e);}
}
public static void main(String[] args) {
try{
go();
} catch(Exception ex){
ex.printStackTrace();
}
System.out.println("An example for updating a Row from Mysql Database!");
Connection con = null;
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://" + rhost +":" + lport + "/";
String db = "testDB";
String dbUser = "wasim";
String dbPasswd = "riponalwasim123";
try{
Class.forName(driver);
con = DriverManager.getConnection(url+db, dbUser, dbPasswd);
try{
Statement st = con.createStatement();
String sql = "UPDATE MyTableName " +
"SET email = 'ripon.wasim@smile.com' WHERE email='peace@happy.com'";
int update = st.executeUpdate(sql);
if(update >= 1){
System.out.println("Row is updated.");
}
else{
System.out.println("Row is not updated.");
}
}
catch (SQLException s){
System.out.println("SQL statement is not executed!");
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
答案 2 :(得分:6)
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
public class CTestDriver {
private static void doSshTunnel(String strSshUser, String strSshPassword, String strSshHost, int nSshPort,
String strRemoteHost, int nLocalPort, int nRemotePort) throws JSchException {
final JSch jsch = new JSch();
Session session = jsch.getSession(strSshUser, strSshHost, 22);
session.setPassword(strSshPassword);
final Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
session.setPortForwardingL(nLocalPort, strRemoteHost, nRemotePort);
}
public static void main(String[] args) {
try {
String strSshUser = "ssh_user_name"; // SSH loging username
String strSshPassword = "abcd1234"; // SSH login password
String strSshHost = "your.ssh.hostname.com"; // hostname or ip or
// SSH server
int nSshPort = 22; // remote SSH host port number
String strRemoteHost = "your.database.hostname.com"; // hostname or
// ip of
// your
// database
// server
int nLocalPort = 3366; // local port number use to bind SSH tunnel
int nRemotePort = 3306; // remote port number of your database
String strDbUser = "db_user_name"; // database loging username
String strDbPassword = "4321dcba"; // database login password
CTestDriver.doSshTunnel(strSshUser, strSshPassword, strSshHost, nSshPort, strRemoteHost, nLocalPort,
nRemotePort);
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:" + nLocalPort, strDbUser,
strDbPassword);
con.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.exit(0);
}
}
}
答案 3 :(得分:2)
虽然现有答案是正确的,但它们却掩盖了其他代码中的重要代码。
这是您需要通过SSH通道建立JDBC(或任何其他)数据库连接的基本代码:
String jumpserverHost = "ssh.example.com";
String jumpserverUsername = "sshuser";
// The hostname/IP address and port, you would use on the SSH server
// to connect to the database.
// If the database runs on the same machine as the SSH server, use "localhost".
String databaseHost = "database.example.com";
int databasePort = 3306;
String databaseUsername = "dbuser";
String databasePassword = "dbpass";
JSch jsch = new JSch();
// Public key authentication example
// (but you can use password authentication, if appropriate).
jsch.addIdentity("~/.ssh/id_rsa");
// Connect to SSH jump server (this does not show an authentication code)
Session session = jsch.getSession(jumpserverUsername, jumpserverHost);
session.connect();
// Forward randomly chosen local port through the SSH channel to database host/port
int forwardedPort = session.setPortForwardingL(0, databaseHost, databasePort);
// Connect to the forward port (the local end of the SSH tunnel)
// If you don't use JDBC, but another database client,
// just connect it to the localhost:forwardedPort
String url = "jdbc:mysql://localhost:" + forwardedPort;
Connection con = DriverManager.getConnection(url, databaseUsername, databasePassword);
您还必须处理主机密钥验证。为此,请参见:
How to resolve Java UnknownHostKey, while using JSch SFTP library?
答案 4 :(得分:0)
首先,谢谢你的作品很棒!
尽管如此,我想知道是否应该为每个(可能同时的)SQL连接重用该Session,或者我是否应该每次都创建一个新的Session,并且只有在某些原因它已经过期时才刷新它。
目前,我每次建立连接时都会在此处创建该Controller的新实例,然后使用我从中获得的连接执行SQL查询,然后手动关闭它。
如果我可以使用try-with-resource使这个类可用并且它自己关闭也会很好。会调查一下。因为我不想错过它。
这是怎么回事,我现在正在接收DB Connections。
public class ConnectionManager {
private Connection con = null;
private Session session = null;
public Connection getConnection() {
Connection con = null;
var settings = new DbSettingsController();
boolean useSSH = settings.getSetting(SettingKey.UseSSH).equals("true");
String sshPort = settings.getSetting(SettingKey.SSHPort);
String sqlIp = settings.getSetting(SettingKey.MySqlIP);
String sqlPort = settings.getSetting(SettingKey.MySqlPort);
if(useSSH) {
JSch jSch = new JSch();
try {
this.session = jSch.getSession(settings.getSetting(SettingKey.SSHUser),
settings.getSetting(SettingKey.SSHHost),
Integer.valueOf(sshPort));
this.session.setPassword(settings.getSetting(SettingKey.SSHPassword));
this.session.setConfig("StrictHostKeyChecking", "no");
this.session.connect();
this.session.setPortForwardingL(Integer.parseInt(sshPort), sqlIp, Integer.parseInt(sqlPort));
} catch (JSchException e) {
e.printStackTrace();
}
}
var connectionString = String.format("jdbc:mysql://%s:%s/%s?autoReconnect=true&useSSL=false",
sqlIp, useSSH ? sshPort : sqlPort,
settings.getSetting(SettingKey.MySqlShema));
var user = settings.getSetting(SettingKey.MySqlUser);
var password = settings.getSetting(SettingKey.MySqlPassword);
try {
con = DriverManager.getConnection(connectionString, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
public void close() {
if(this.con != null) {
try {
this.con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(this.session != null) {
this.session.disconnect();
}
}
如果您想知道DbSettingsController我自己也做了,只需将设置放在本地SQLite DB的Text列中,并为其分配一个键(即enum的int值)。只是复制粘贴代码我从其他项目中重复使用,所以这样做很简单快捷。