简体   繁体   English

处理Java OOP风格的SQL数据库连接的正确方法

[英]Proper way to handle SQL database connections in java OOP style

I recently did a programming challenge. 我最近遇到了编程挑战。 It was an OOP challenge to expose an API for managing a fictitious movie rental company. 公开用于管理虚拟电影租赁公司的API是一个OOP挑战。 I chose to use sparkjava, and worked from a heroku template. 我选择使用sparkjava,并使用heroku模板进行工作。 I have posted the code to Github here , and invite anyone to query the URL provided in the README doc. 我已经在此处将代码发布到Github上 ,并邀请任何人查询README文档中提供的URL。 The secret password is secret . 秘密密码是secret

I received a lot of good feedback about things that need improvement. 对于需要改进的事情,我收到了很多很好的反馈。 One objection is: 一个反对意见是:

Handling connections directly vi the driver, without any handling for closing connections properly. 直接通过驱动程序处理连接,而无需进行任何正确关闭连接的处理。

So I am trying to figure out what this means, why its a problem, and how to fix it and make my code better. 所以我试图弄清楚这意味着什么,为什么会出现问题,以及如何解决它并使我的代码更好。

For example I have this method, in the main class : 例如我在主类中有此方法:

public static int validate_customer(String cust) throws SQLException, URISyntaxException {
    int customer = 0;
    try{
        customer = Integer.parseInt(cust);
    }catch (Exception e){
        throw new SQLException("Invalid customer integer -> " + cust);
    }

    Connection connection = DatabaseUrl.extract().getConnection();
    PreparedStatement stmt = connection.prepareStatement("SELECT count(*) from customers where id = ?;");
    stmt.setInt(1, customer);
    ResultSet rs = stmt.executeQuery();
    rs.next();
    if ( rs.getInt(1) < 1 ){
        throw new SQLException("Invalid customer id -> " + customer);
    }
    rs.close();
    stmt.close();
    return customer;
}

Why is this an incorrect way to handle interaction with the DB? 为什么这是处理与数据库交互的不正确方法? There are other methods there in the main class which interact with the DB but the technique is basically the same as this example. 主类中还有其他与DB交互的方法,但是该方法与本示例基本相同。

To me, if there was a problem with the connection to the database, it would occur in the line: Connection connection = DatabaseUrl.extract().getConnection(); 对我而言,如果与数据库的连接存在问题,则将在以下行中发生: Connection connection = DatabaseUrl.extract().getConnection(); and throw an SQLException . 并抛出一个SQLException If somethings happens to the connection, and some part of the query doesn't work, an exception will be thrown from this validate_customer method. 如果连接发生问题,并且查询的某些部分不起作用,则此validate_customer方法将引发异常。 Why is this a problem in my code? 为什么这在我的代码中有问题?

Handling connections directly vi the driver 直接通过驱动程序处理连接

This means you are not using a DB connection pool (like HikariCP ), which means it's possible exhaust your connection limit very quickly. 这意味着您没有使用数据库连接池(例如HikariCP ),这意味着有可能很快耗尽连接限制。 The Heroku example does not use a DB connection pool to limit dependencies in the example. Heroku示例不使用数据库连接池来限制示例中的依赖关系。

without any handling for closing connections properly. 没有适当关闭连接的任何处理。

This means the stmt.close(); 这意味着stmt.close(); is not a in a finally block, which means if an exception is thrown in the method the stmt will never be closed. finally块中不是,这意味着如果在方法中引发异常,则stmt将永远不会关闭。

I often see the closing of connections done in a the finally block of a try catch. 我经常在try catch的finally块中看到关闭连接。 Perhaps handling the SQL Exception inside the method within a try catch statement would be better and closing the resources within the finally block. 也许在try catch语句中的方法内部处理SQL Exception会更好,并且可以关闭finally块中的资源。 This is just what I often see. 这就是我经常看到的。 I hope it may have helped. 希望对您有所帮助。


To update this, Java 7 introduces a feature named 'try-with-resources'. 为了对此进行更新,Java 7引入了一个名为“ try-with-resources”的功能。 This seems to be the new preferred way of cleaning up resources. 这似乎是清理资源的新首选方式。 To provide an example: 举个例子:

try(Connection connection = Connection.getConnection();
    PreparedStatement stmt = connection.prepareStatement("..."))
{
    ...
}

A try with resources will automatically close any resources which implement the AutoClosable interface and are declared in the parenthesis of a try statement. 尝试使用资源将自动关闭实现AutoClosable接口并在try语句的括号中声明的所有资源。

Here is a link to the official tutorial documentation: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html 这是官方教程文档的链接: https : //docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

I'd recommend you to use a datasource . 我建议您使用数据源 Have you in your classpath the dependencies for the datasource and the jdbc database specific driver. 在类路径中,您具有数据源和特定于jdbc数据库的驱动程序的依赖性。 In this case I'm using dbcp2 and mysql . 在这种情况下,我使用的是dbcp2mysql

public long count(final int customerId) {

    int count;

    final String query = "SELECT count(*) FROM customers WHERE id = ?";

    try (final Connection conn = dataSource.getConnection();
         final PreparedStatement prepStatement = conn.prepareStatement(query)) {

        prepStatement.setInt(1, customerId);

        final ResultSet rs = prepStatement.executeQuery();

        rs.next();
        count = rs.getInt(1);

    } catch (SQLException e) {

        // You may want to log and throw a custom exception here.
        throw new RuntimeException(e);
    }

    return count;
}

public DataSource dataSource() {

    final org.apache.commons.dbcp2.BasicDataSource dataSource =
        new org.apache.commons.dbcp2.BasicDataSource();

    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl(environment.getProperty("jdbc:mysql://localhost:3306/myDatabase"));
    dataSource.setUsername(environment.getProperty("root"));
    dataSource.setPassword(environment.getProperty("password"));

    return dataSource;
}

Notice I'm not explicitly closing the connection on a finally block because since Java 7 the Connection and the PreparedStatement are auto-closeable resources . 注意,我没有在finally块上显式关闭连接,因为自Java 7以来, ConnectionPreparedStatement是可自动关闭的资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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