繁体   English   中英

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

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

我最近遇到了编程挑战。 公开用于管理虚拟电影租赁公司的API是一个OOP挑战。 我选择使用sparkjava,并使用heroku模板进行工作。 我已经在此处将代码发布到Github上 ,并邀请任何人查询README文档中提供的URL。 秘密密码是secret

对于需要改进的事情,我收到了很多很好的反馈。 一个反对意见是:

直接通过驱动程序处理连接,而无需进行任何正确关闭连接的处理。

所以我试图弄清楚这意味着什么,为什么会出现问题,以及如何解决它并使我的代码更好。

例如我在主类中有此方法:

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;
}

为什么这是处理与数据库交互的不正确方法? 主类中还有其他与DB交互的方法,但是该方法与本示例基本相同。

对我而言,如果与数据库的连接存在问题,则将在以下行中发生: Connection connection = DatabaseUrl.extract().getConnection(); 并抛出一个SQLException 如果连接发生问题,并且查询的某些部分不起作用,则此validate_customer方法将引发异常。 为什么这在我的代码中有问题?

直接通过驱动程序处理连接

这意味着您没有使用数据库连接池(例如HikariCP ),这意味着有可能很快耗尽连接限制。 Heroku示例不使用数据库连接池来限制示例中的依赖关系。

没有适当关闭连接的任何处理。

这意味着stmt.close(); finally块中不是,这意味着如果在方法中引发异常,则stmt将永远不会关闭。

我经常在try catch的finally块中看到关闭连接。 也许在try catch语句中的方法内部处理SQL Exception会更好,并且可以关闭finally块中的资源。 这就是我经常看到的。 希望对您有所帮助。


为了对此进行更新,Java 7引入了一个名为“ try-with-resources”的功能。 这似乎是清理资源的新首选方式。 举个例子:

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

尝试使用资源将自动关闭实现AutoClosable接口并在try语句的括号中声明的所有资源。

这是官方教程文档的链接: https : //docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

我建议您使用数据源 在类路径中,您具有数据源和特定于jdbc数据库的驱动程序的依赖性。 在这种情况下,我使用的是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;
}

注意,我没有在finally块上显式关闭连接,因为自Java 7以来, ConnectionPreparedStatement是可自动关闭的资源

暂无
暂无

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

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