将Java连接到MySQL数据库

365

如何在Java中连接MySQL数据库?

当我尝试时,我得到了

java.sql.SQLException: No suitable driver found for jdbc:mysql://database/table
    at java.sql.DriverManager.getConnection(DriverManager.java:689)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
或者
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

或者

java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver

1
这是一个短短3分钟的视频教程,演示了如何从Java中使用MySQL。在这里查看:快速教程:使用Java连接MySQL数据库 - drorw
14个回答

535
以下是逐步解释如何安装MySQL和JDBC以及如何使用它的步骤:
  1. 下载并安装MySQL服务器。按照通常的方式进行操作。记住端口号,如果你已经更改了它。默认端口号是3306

  2. 下载JDBC驱动程序并将其放入类路径中,解压ZIP文件并将包含的JAR文件放入类路径中。特定供应商的JDBC驱动程序是JDBC API的具体实现(这里有教程)。

    如果你使用Eclipse或Netbeans等IDE,则可以通过将JAR文件添加为项目属性中的构建路径中来将其添加到类路径中。

    如果你在命令控制台中进行操作,则需要在执行Java应用程序时在-cp-classpath参数中指定JAR文件的路径。

    java -cp .;/path/to/mysql-connector.jar com.example.YourClass

    这里的.是为了将当前目录添加到类路径中,以便它可以找到com.example.YourClass,而;是类路径分隔符,就像在Windows中一样。在Unix和克隆系统中应该使用:

    如果你正在开发基于servlet的WAR应用程序并希望手动管理连接(实际上是不好的做法),那么你需要确保JAR文件最终位于构建的/WEB-INF/lib目录中。另一种更好的做法是将物理JDBC驱动程序JAR文件安装在服务器本身,并配置服务器创建JDBC连接池。这里有一个Tomcat的示例:在基于servlet的应用程序中如何连接到JDBC数据库/数据源?

  3. 在MySQL中创建一个数据库。让我们创建一个名为javabase的数据库。当然,你想要世界统治,所以让我们也使用UTF-8。

    CREATE DATABASE javabase DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
  4. 为Java创建一个用户授予访问权限。只是因为使用root是一个不好的做法。

    CREATE USER 'java'@'localhost' IDENTIFIED BY 'password';
    GRANT ALL ON javabase.* TO 'java'@'localhost' IDENTIFIED BY 'password';

    是的,这里的用户名是java,密码是password

  5. 确定JDBC URL。要使用Java连接MySQL数据库,你需要一个JDBC URL,其语法如下:

    jdbc:mysql://hostname:port/databasename
    • hostname:安装MySQL服务器的主机名。如果它安装在运行Java代码的同一台机器上,那么你可以使用localhost。它也可以是一个IP地址,如127.0.0.1。如果你遇到连接问题,并且使用127.0.0.1而不是localhost解决了问题,那么你的网络/DNS/主机配置存在问题。

    • port:MySQL服务器监听的TCP/IP端口。默认端口号是3306

    • databasename:你想要连接的数据库的名称。这里是javabase

    所以最终的URL应该是:

    jdbc:mysql://localhost:3306/javabase
  6. 使用Java测试与MySQL的连接。创建一个简单的Java类,其中包含一个main()方法来测试连接。

    String url = "jdbc:mysql://localhost:3306/javabase";
    String username = "java";
    String password = "password";
    
    System.out.println("连接数据库...");
    
    try (Connection connection = DriverManager.getConnection(url, username, password)) {
        System.out.println("数据库已连接!");
    } catch (SQLException e) {
        throw new IllegalStateException("无法连接数据库!", e);
    }

    如果你得到一个SQLException: No suitable driver,那么这意味着JDBC驱动程序根本没有自动加载,或者JDBC URL是错误的(即它没有被任何加载的驱动程序识别)。另请参阅臭名昭著的java.sql.SQLException: No suitable driver found。通常,当你将JDBC 4.0驱动程序放入运行时类路径中时,它应该被自动加载。为了排除一种和另一种情况,你总是可以手动加载它,如下所示:

    System.out.println("加载驱动程序...");
    
    try {
        Class.forName("com.mysql.cj.jdbc.Driver"); // 如果你还没有使用MySQL 8+,请使用com.mysql.jdbc.Driver。
        System.out.println("驱动程序已加载!");
    } catch (ClassNotFoundException e) {
        throw new IllegalStateException("在类路径中找不到驱动程序!", e);
    }

    请注意,这里不需要调用newInstance()。这只是为了修复旧的有缺陷的org.gjt.mm.mysql.Driver这里有解释。如果这一行抛出ClassNotFoundException,那么包含JDBC驱动程序类的JAR文件根本没有放置在类路径中。还请注意,抛出异常非常重要,这样可以立即阻止代码执行,而不是将其抑制或仅打印堆栈跟踪,然后继续执行其余的代码。

    还要注意,你不需要在每次连接之前都加载驱动程序。只需要在应用程序启动时加载一次即可。

    如果你得到一个SQLException: Connection refusedConnection timed out,或者MySQL特定的CommunicationsException: Communications link failure,那么这意味着DB根本无法访问。这可能有以下一个或多个原因:

    1. JDBC URL中的IP地址或主机名是错误的。
    2. JDBC URL中的主机名未被本地DNS服务器识别。
    3. JDBC URL中缺少或错误的端口号。
    4. DB服务器已关闭。
    5. DB服务器不接受TCP/IP连接。
    6. DB服务器的连接已用尽。
    7. Java和DB之间的某个地方阻止连接,例如防火墙或代理。

    要解决其中的一个或另一个问题,请遵循以下建议:

    1. 使用ping验证和测试它们。
    2. 刷新DNS或在JDBC URL中使用IP地址。
    3. 根据MySQL DB的my.cnf文件进行验证。
    4. 启动DB。
    5. 验证mysqld是否没有使用--skip-networking选项启动。
    6. 重新启动DB,并相应地修复你的代码,确保在finally中关闭连接。
    7. 禁用防火墙和/或配置防火墙/代理以允许/转发端口。

    请注意,关闭Connection非常重要。如果你不关闭连接,并在短

    那就是关于连接性的问题。你可以在这里找到一个更高级的教程,教你如何使用基本的DAO类将完整的Java模型对象加载和存储到数据库中。
    使用单例模式和/或静态变量来处理数据库连接是一种不好的做法。请参考在多线程系统中使用静态java.sql.Connection实例是否安全?这是初学者常犯的错误之一。确保不要陷入这个陷阱。

我也遇到了同样的错误。更新驱动程序版本对我有用。https://downloads.mysql.com/archives/c-j/ - Nafees Ahmad
连接到MySQL Docker容器时,JDBC URL中的主机名和端口值应该是什么?是localhost还是172.17.0.1(docker0)或者MySQL服务名称? - undefined
1
@marc:主机名确实是Docker服务名称(services对象的键)。端口是您在端口配置中指定的第二个值。如果是3306:3306,那么仍然是3306 - undefined
@BalusC:我通过将database.driver的值从com.mysql.jdbc.Driver更改为com.mysql.jdbc.driver来解决了连接被拒绝的错误。然而,真的是因为大小写字母的问题吗?我只是想确认一下,谢谢。 - undefined

231

数据源

DriverManager是一种相对较旧的方法。更好的方法是获取一个数据源对象。可以通过使用JNDI来查找已经为您配置的应用服务器容器中的数据源:

Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/myDB");

…或者通过直接实例化和配置一个来自您的数据库驱动程序,例如com.mysql.cj.jdbc.MysqlDataSource请参阅文档):
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUser("scott");
dataSource.setPassword("tiger");
dataSource.setServerName("myDBHost.example.org");

…然后从中获取连接,与上述相同:
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT ID FROM USERS");
…
rs.close();
stmt.close();
conn.close();

在现代的Java中,使用try-with-resources语法来自动关闭JDBC资源(现在是AutoCloseable)。
try (
    Connection conn = dataSource.getConnection();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT ID FROM USERS");
) {
    …
}

8
我认为这是旧式的Driver类,可以与旧式的驱动程序机制配合使用。MysqlDataSource实现了较新的机制javax.sql.DataSource - Sean Owen
1
嗨@SeanOwen,我想知道为什么我们要关闭 rsstmt? 为什么不只关闭 conn - Kamuran Sönecek
4
也许你应该添加 dataSource.setDatabaseName("database")。 - Myoch
2
明确关闭事物是一个好的实践,尽管它需要更多的代码。任何好的实现都必须在连接关闭时关闭资源。但考虑其他想要重用语句或连接的情况。在Java 7的try-with-resources中,你可以免费获得这种行为。 - Sean Owen
1
在过去,曾经有一些臭名昭著的JDBC驱动程序无法正确地级联关闭这些JDBC对象,从而违反了JDBC规范的要求。这些关键的缺陷教会了我们养成一个习惯,即明确关闭每个单独的JDBC资源。现在,这变得非常简单:在现代的Java中,JDBC资源实现了AutoCloseable接口,因此我们可以使用非常简单的try-with-resources语法来自动关闭。 - undefined
显示剩余8条评论

47

初始化数据库常量

创建常量属性数据库用户名、密码、URL和驱动程序、轮询限制等。

// init database constants
// com.mysql.jdbc.Driver
private static final String DATABASE_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/database_name";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
private static final String MAX_POOL = "250"; // set your own limit

初始化连接和属性

一旦建立连接,最好将其存储以便于重复使用。

// init connection object
private Connection connection;
// init properties object
private Properties properties;

创建属性

属性对象保存连接信息,请检查是否已经设置。

// create properties
private Properties getProperties() {
    if (properties == null) {
        properties = new Properties();
        properties.setProperty("user", USERNAME);
        properties.setProperty("password", PASSWORD);
        properties.setProperty("MaxPooledStatements", MAX_POOL);
    }
    return properties;
}

连接数据库

现在使用已初始化的常量和属性连接到数据库。

// connect database
public Connection connect() {
    if (connection == null) {
        try {
            Class.forName(DATABASE_DRIVER);
            connection = DriverManager.getConnection(DATABASE_URL, getProperties());
        } catch (ClassNotFoundException | SQLException e) {
            // Java 7+
            e.printStackTrace();
        }
    }
    return connection;
}

断开数据库连接

完成数据库操作后,只需关闭连接即可。

// disconnect database
public void disconnect() {
    if (connection != null) {
        try {
            connection.close();
            connection = null;
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

所有东西放在一起

在更改database_name、username和password等信息后,直接使用这个类MysqlConnect

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class MysqlConnect {
    // init database constants
    private static final String DATABASE_DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/database_name";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static final String MAX_POOL = "250";

    // init connection object
    private Connection connection;
    // init properties object
    private Properties properties;

    // create properties
    private Properties getProperties() {
        if (properties == null) {
            properties = new Properties();
            properties.setProperty("user", USERNAME);
            properties.setProperty("password", PASSWORD);
            properties.setProperty("MaxPooledStatements", MAX_POOL);
        }
        return properties;
    }

    // connect database
    public Connection connect() {
        if (connection == null) {
            try {
                Class.forName(DATABASE_DRIVER);
                connection = DriverManager.getConnection(DATABASE_URL, getProperties());
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
        }
        return connection;
    }

    // disconnect database
    public void disconnect() {
        if (connection != null) {
            try {
                connection.close();
                connection = null;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

如何使用?

初始化数据库类。

// !_ note _! this is just init
// it will not create a connection
MysqlConnect mysqlConnect = new MysqlConnect();

在您的代码中的其他位置...

String sql = "SELECT * FROM `stackoverflow`";
try {
    PreparedStatement statement = mysqlConnect.connect().prepareStatement(sql);
    ... go on ...
    ... go on ...
    ... DONE ....
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    mysqlConnect.disconnect();
}

这就是全部:)如果需要改进,请进行编辑!希望这有所帮助。


马克,每个类在需要与数据交互时是否都需要保持自己独立的MysqlConnect实例处于打开状态?我只是想知道这种设置在类之间是如何工作的。 - Michael Sims
应使用 jdbc:mysql://localhost:3306/stocks 而不是废弃的 com.mysql.jdbc.Driver - StealthTrails
如果你要硬编码账户名、密码、数据库名等信息,这种方式非常笨拙。只需将所有这些细节放入JDBC URL字符串中即可。(包括池大小...) - Stephen C
我建议使用DataSource的实现,而不是这些硬编码的属性。例如:com.mysql.cj.jdbc.MysqlDataSource。请参阅文档 - undefined
我建议使用DataSource的实现,而不是这些硬编码的属性。例如:com.mysql.cj.jdbc.MysqlDataSource。请参阅文档。请参阅Sean Oven的回答 - undefined

27
String url = "jdbc:mysql://127.0.0.1:3306/yourdatabase";
String user = "username";
String password = "password";

// Load the Connector/J driver
Class.forName("com.mysql.jdbc.Driver").newInstance();
// Establish connection to MySQL
Connection conn = DriverManager.getConnection(url, user, password);

这里的数据库是什么?数据库名称是什么? - Koray Tugay
newInstance() 不是必需的。是吗? - Mohamed Ennahdi El Idrissi
1
不是这样的。自从Java 6以来,整个方法已经过时了。而且驱动程序类名也已经更改了...... - Stephen C
有趣的是,在DriverManager的文档中https://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html中指出,不再需要使用Class.forName(),而是可以使用一些属性文件java.sql.Driver。 - vmrvictor
数据库名称似乎是“yourdatabase”,正如您在URL中所看到的。 - vmrvictor

13

这是从MySQL数据库中获取数据所需的最少要求:

Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection
   ("jdbc:mysql://localhost:3306/foo", "root", "password");

Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM `FOO.BAR`");
stmt.close();
conn.close();

根据个人喜好添加异常处理、配置等内容。


3
为什么需要使用Class.forName(...).newInstance()?这个表达式可以动态地创建一个类的实例。Class.forName(...)返回一个类对象,然后调用它的newInstance()方法就可以创建该类的新实例。这在需要根据程序运行时的条件来确定使用哪个类的实例时非常有用。 - Don Cheadle
8
自从2007年起,您就不需要这样做了。 - user207421

3
你需要在类路径中拥有mysql连接器jar。
在Java中,JDBC API可以与数据库进行交互。使用JDBC,我们可以编写Java应用程序来:
1. 向DB(任何关系型数据库)发送查询或更新SQL语句 2. 检索并处理来自DB的结果
通过以下三个步骤,我们可以从任何数据库检索数据。
Connection con = DriverManager.getConnection(
                     "jdbc:myDriver:DatabaseName",
                     dBuserName,
                     dBuserPassword);

Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table");

while (rs.next()) {
    int x = rs.getInt("a");
    String s = rs.getString("b");
    float f = rs.getFloat("c");
}

2

使用SSL连接MySQL JDBC。

private String db_server = BaseMethods.getSystemData("db_server");
private String db_user = BaseMethods.getSystemData("db_user");
private String db_password = BaseMethods.getSystemData("db_password");

private String connectToDb() throws Exception {
   String jdbcDriver = "com.mysql.jdbc.Driver";
   String dbUrl = "jdbc:mysql://" + db_server  +
        "?verifyServerCertificate=false" +
        "&useSSL=true" +
        "&requireSSL=true";
    System.setProperty(jdbcDriver, "");
    Class.forName(jdbcDriver).newInstance();

    Connection conn = DriverManager.getConnection(dbUrl, db_user, db_password);
    Statement statement = conn.createStatement();
    String query = "SELECT EXTERNAL_ID FROM offer_letter where ID =" + "\"" + letterID + "\"";
    ResultSet resultSet = statement.executeQuery(query);
    resultSet.next();
    return resultSet.getString(1);
}

查询字符串的创建方式是一种非常糟糕的做法,容易受到SQL注入攻击的威胁。 - BigMac66

2

简洁明了的代码。

try {       
    Class.forName("com.mysql.jdbc.Driver");
    System.out.println("Driver Loaded");
    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testDB","root","");
    //Database Name - testDB, Username - "root", Password - ""
    System.out.println("Connected...");         
} catch(Exception e) {
    e.printStackTrace();
}

针对 SQL Server 2012

try {
    String url = "jdbc:sqlserver://KHILAN:1433;databaseName=testDB;user=Khilan;password=Tuxedo123"; 
    //KHILAN is Host    and 1433 is port number     
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    System.out.println("Driver Loaded");
    conn = DriverManager.getConnection(url);
    System.out.println("Connected...");
} catch(Exception e) {
    e.printStackTrace();
}

2

1

连接(Connection)是我以前使用的一种方法,看起来是最简单的方式,但也建议在那里加上if语句-确切地说

Connection con = DriverManager.getConnection(
                     "jdbc:myDriver:DatabaseName",
                     dBuserName,
                     dBuserPassword);
if (con != null){
 //..handle your code there 
}

或者类似这样的方式 :)

可能会出现某种情况,getConnection 可能会返回 null :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接