简体   繁体   中英

SQLException on database connection: No suitable driver found for jdbc:mysql://localhost:3306/smtbiz

Problem: I am trying to create a self contained file for running my JDBC application which interfaces with a front end created using javafx. The program works perfectly fine when running it from the IDE (NetBeans) however when trying to run the application utilising my own batch files for; compiling, creating a custom JRE, creating a custom JAR and launch I run into this error:

SQLException on database connection: No suitable driver found for jdbc:mysql://localhost:3306/smtbiz

SQLState: 08001

Solutions tried: including the mysql-connect.jar in the project library and including it in the compile time classpath location. I have had a good look at existing posts. Help is much much appreciated.

Main class

public class CustomerManagementGUI extends Application {

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("CustomerManagementUI.fxml"));
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
}

public static void main(String[] args) {
    //launch(args);
    Scanner sc = new Scanner(System.in);
    CustomerManagementGUI.launch(args);
    CreateDatabase.createCustomerDB();

}

Database utility function class

public class DBUtil {

private static final String URL_DB = "jdbc:mysql://localhost:3306/smtbiz";
private static final String USER = "root";
private static final String PASSWORD = "";
private static Connection con = null;

public static void connectDatabase() {
    try {
        con = DriverManager.getConnection(URL_DB, USER, PASSWORD);
        con.setAutoCommit(false);
    } catch (SQLException ex) {
        System.out.println("SQLException on database connection: " + ex.getMessage());
        System.out.println("SQLState: " + ex.getSQLState());
        System.out.println("VendorError: " + ex.getErrorCode());
    }
}

public static void closeDatabase() {
    try {
        if (con != null && !con.isClosed()) {
            con.close();
        }
    } catch (SQLException ex) {
        System.out.println("SQLException on database close: " + ex.getMessage());
    }
}

public static ResultSet executeQuery(String queryStmt) {
    Statement stmt = null;
    ResultSet resultSet = null;
    CachedRowSet crs = null;
    try {
        connectDatabase();
        stmt = con.createStatement();
        resultSet = stmt.executeQuery(queryStmt);
        crs = RowSetProvider.newFactory().createCachedRowSet();
        crs.populate(resultSet);
    } catch (SQLException ex) {
        System.out.println("SQLException on executeQuery: " + ex.getMessage());
    } finally {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            closeDatabase();
        } catch (SQLException ex) {
            System.out.println("SQLException caught on database closing: " + ex.getMessage());
        }
    }
    return crs;
}

public static int executeUpdate(String sqlStmt) {
    Statement stmt = null;
    int count;
    try {
        connectDatabase();
        stmt = con.createStatement();
        count = stmt.executeUpdate(sqlStmt);
        con.commit();
        return count;
    } catch (SQLException ex) {
        System.out.println("SQLException on executeUpdate: " + ex.getMessage());
        return 0;
    } finally {
        try {
            if (stmt != null) {
                stmt.close();
            }
            closeDatabase();
        } catch (SQLException ex) {
            System.out.println("SQLException caught on database closing: " + ex.getMessage());
        }
    }
}

DAO Class

public class CustomerDAO {

public static void insertCustomer(String name, String email, String mobile) {
    String insertSQL = String.format("INSERT INTO customer (Name, Email, Mobile) VALUES ('%s', '%s', '%s');",
            name, email, mobile);
    int count = DBUtil.executeUpdate(insertSQL);
    if (count == 0) {
        System.out.println("Failed to add new customer.");
    } else {
        System.out.println("\nNew customer added successfully.");
    }
    
}

public static void deleteCustomer(int customerID) {
    String deleteSQL = "DELETE FROM customer WHERE id='" + customerID + "';";
    int count = DBUtil.executeUpdate(deleteSQL);
    if (count == 0) {
        System.out.println("ID not found, delete unsuccessful.");
    } else {
        System.out.println("\nID successfully deleted.");
    }
}

public static void editCustomer(int customerID, String customerName, String customerEmail, String customerMobile) {
    String editCustomer = "UPDATE customer "
            + "SET name = " + "\"" + customerName + "\", " + "email = " + "\"" + customerEmail + "\", " + "mobile = " + "\"" + customerMobile + "\" "
            + "WHERE ID = " + "" + customerID + ";";

    int count = DBUtil.executeUpdate(editCustomer);
    if (count == 0) {
        System.out.println("ID not found, edit unsuccessful.");
    } else {
        System.out.println("\nID successfully edited.");
    }
}

public static Customer searchCustomerID(int id) throws SQLException {
    String query = "SELECT * FROM customer WHERE ID =" + id + ";";
    Customer c = null;
    try {
        ResultSet rs = DBUtil.executeQuery(query);
        if (rs.next()) {
            System.out.println("\nCustomer found: ");
            c = new Customer();
            c.setId(rs.getInt("ID"));
            c.setName(rs.getString("Name"));
            c.setEmail(rs.getString("Email"));
            c.setMobile(rs.getString("Mobile"));
        } else if (c == null){
            System.out.println("Unfortunately that customer ID: " + id + " was not found.");
        }
        else {
            System.out.println("Unfortunately that customer ID: " + id + " was not found.");
        }
    } catch (SQLException ex) {
        System.out.println("SQLException on executeQuery: " + ex.getMessage());
    }
    return c;
}

public static ObservableList<Customer> getAllCustomers() throws ClassNotFoundException, SQLException {

    String query = "SELECT * FROM customer;";
    try {
        ResultSet rs = DBUtil.executeQuery(query);
        ObservableList<Customer> customerDetails = getCustomerModelObjects(rs);

        return customerDetails;
    } catch (SQLException ex) {
        System.out.println("Error!");
        ex.printStackTrace();;
        throw ex;
    }

}

public static ObservableList<Customer> getCustomerModelObjects(ResultSet rs) throws SQLException, ClassNotFoundException {
    try {
        ObservableList<Customer> customerList = FXCollections.observableArrayList();
        while (rs.next()) {
            Customer customer = new Customer();
            customer.setId(rs.getInt("ID"));
            customer.setName(rs.getString("Name"));
            customer.setEmail(rs.getString("Email"));
            customer.setMobile(rs.getString("Mobile"));
            customerList.add(customer);
        }
        return customerList;
    } catch (SQLException ex) {
        throw ex;
    }

}

Customer Object Class Not included: to save post space.

Create Database Class

public class CreateDatabase {

public static void createCustomerDB() {
    String url = "jdbc:mysql://localhost:3306/"; // no database yet
    String user = "root";
    String password = "";
    Connection con = null;
    Statement stmt = null;
    String query;
    ResultSet result = null;
    try {
        con = DriverManager.getConnection(url, user, password);
        stmt = con.createStatement();

        query = "DROP DATABASE IF EXISTS smtbiz;";
        stmt.executeUpdate(query);

        query = "CREATE DATABASE smtbiz;";
        stmt.executeUpdate(query);

        query = "USE smtbiz;";
        stmt.executeUpdate(query);

        query = """
                CREATE TABLE customer (
                ID INTEGER NOT NULL AUTO_INCREMENT,
                Name VARCHAR(32),
                Email VARCHAR(25),
                Mobile VARCHAR(15),
                PRIMARY KEY(ID)
                );
                """;
        stmt.executeUpdate(query);

        query = """
                INSERT INTO customer
                (Name,Email,Mobile)
                VALUES
                ("Kyle","Kyle.Henry@gmail.com","0489358318"),
                ("John","John.Potter@outlook.com","0460358348"),
                ("Liam","Liam.Stone@hotmail.com","0417335874"),
                ("Argon","Argon.Chung@gmail.com","0422358320"),
                ("Kris","Kris.Frank@gmail.com","0494358923");
                """;
        stmt.executeUpdate(query);
        query = "SELECT * FROM customer;";
        result = stmt.executeQuery(query); // execute the SQL query
    } catch (SQLException ex) {
        System.out.println("SQLException on database creation: " + ex.getMessage());
    } finally {
        try {
            if (result != null) {
                result.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (con != null) {
                con.close();
            }
        } catch (SQLException ex) {
            System.out.println("SQLException caught: " + ex.getMessage());
        }
    }
}

Below I have included the batch files used:

Compile Batch

@echo off
javac --module-path %PATH_TO_FX% --add-modules=javafx.base,javafx.controls,javafx.fxml,javafx.graphics src\customermanagementgui\*.java -d classes 
copy src\customermanagementgui\*.fxml classes\customermanagementgui\*.fxml
pause

Create JAR batch

@echo off
md app
jar --create --file=app/CustomerManagementGUI.jar --main-class=customermanagementgui.CustomerManagementGUI -m Manifest.mf -C classes .
REM md app\lib
REM copy lib\mysql-connector-java.jar app\lib
xcopy .\lib\ .\app\lib /E /I
pause

Create JRE batch

@echo off
jdeps -s --module-path %PATH_TO_FX% app\CustomerManagementGUI.jar
jlink --module-path ../jmods;%PATH_TO_FX_JMOD% --add-modules java.base,java.sql,java.sql.rowset,javafx.base,javafx.controls,javafx.fxml,javafx.graphics --output jre
echo ############
echo # Finished #
echo ############
pause

Launch Application Batch

@echo off
REM java -classpath classes customermanagementgui.CustomerManagementGUI
jre\bin\java -jar app/CustomerManagementGUI.jar
pause

Placing required jars on the classpath

Let's assume that you have an app directory in your image which follows the standard image directory layout and have placed both the mysql-connector-java jar and your application jar in that app directory (as well as any additional non-modular jars which you want to run from the classpath). Then you can do the following:

Change your launch application batch file to use this command:

bin\java -classpath app\* customermanagementgui.CustomerManagementGUI

What this will do is run both your app and the MySQL connector off of the classpath (placing them in the unnamed module). The Java runtime and JavaFX components are modular and you have already packed them into your runtime image, so you don't need any additional module arguments.

The command does not use an executable jar with the -jar command as that does not allow adding items outside of the jar command to the classpath :

When you use -jar, the specified JAR file is the source of all user classes, and other class path settings are ignored.

On Shading

You could shade the MySQL connector jar file into your application file by unpacking both into the same directory, then repacking them. But, it would seem better to me just to leave the app unshaded and use the classpath command-line switch to add jars for the unnamed module.

The primary useful things about a shaded jar are it is a single file and that it has a short execution command. But you already have lots of files because you have the jlink image. Also, you have a batch file to perform the execution. So you gain no benefit from a shaded jar (IMO).

If shading is used, care also needs to be taken to not include JavaFX modules in the shaded jar, as they are not supported in that execution mode.

Additional Info

The nicest thing would be to just link a MySQL connector module (and an application module you define) into the jlink image you are creating. However, currently, the MySQL connector does not define a module-info file, so it is not linkable. If placed on the module path, the current MySQL connector implementation would become an automatic module .

If you need an installer for your application, then you should use jpackage .

More information on packaging JavaFX applications can be found in:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM