Java 在多个类方法中使用相同的BasicDataSource、Connection、Statement和ResultSet对象可以吗。?

Java 在多个类方法中使用相同的BasicDataSource、Connection、Statement和ResultSet对象可以吗。?,java,maven,debugging,garbage-collection,apache-commons-dbcp,Java,Maven,Debugging,Garbage Collection,Apache Commons Dbcp,下面的代码使用BasicDataSource、Sql连接、语句和ResultSet的静态对象。下面的代码运行良好,但我只想知道使用这种编码实践的安全性。或者我如何优化下面的代码,使其变得更加稳定和可靠 public class Testing { static BasicDataSource bds = DBConnection.getInstance().getBds(); static Connection con = null; static Prepared

下面的代码使用BasicDataSource、Sql连接、语句和ResultSet的静态对象。下面的代码运行良好,但我只想知道使用这种编码实践的安全性。或者我如何优化下面的代码,使其变得更加稳定和可靠

public class Testing {
     static BasicDataSource bds = DBConnection.getInstance().getBds();
     static Connection con = null;
     static PreparedStatement stmt = null;
     static ResultSet rs = null;

    private void show() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("SELECT * FROM users");
            rs = stmt.executeQuery();
            if(rs.next()) {
                System.out.println(rs.getString("firstname") + " " + rs.getString("lastname"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private void display() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("SELECT * FROM agent_cities");
            rs = stmt.executeQuery();
            while(rs.next()) {
                System.out.println(rs.getString("city_name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private void add() {
        try {
            con = bds.getConnection();
            stmt = con.prepareStatement("UPDATE users SET firstname = 'shsh' WHERE id = 2");
            stmt.executeUpdate();
            System.out.println("updated successfully");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        Testing t = new Testing();
        t.show();
        t.display();
        t.add();
    }
}
提前谢谢。 请分享您可以破解上述代码并质疑其安全性的案例

更新: 只更新以确保并没有人应该像我在上面的程序中使用的那个样使用静态字段,因为上面的程序在部署到dev服务器上时包含bug

在大型系统上使用上述代码后,我发现了错误。一个月前,我对上面的代码没有任何问题,它工作得很好,但今天我发现了错误

错误:

在点击我的API 6-7次后,它在第8次点击时停止响应。我真的不知道为什么,也不知道程序中存在循环漏洞。 但是现在我接受了答案,我更改了源代码,开始在代码中使用try-with-resources并删除了静态字段

但是我仍然很想知道我在上面的代码中发现的bug。 这不会给出响应,并在7-8次API命中后挂起。 请分享你的想法。我使用的是ApacheTomcat8.5.32服务器。
提前谢谢。

如果我们讨论的是这样一个小程序,或多或少都可以。 但不需要将con、stmt和rs作为静态变量,它们可以在方法中声明。此外,您还需要重写try-catch-finally块并正确关闭资源:

Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
  // your code
} catch (SQLException e) {
  e.printStackTrace();
} finally {
  try { if (rs != null) rs.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (stmt != null) stmt.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (conn != null) conn.close(); } catch (Exception e) {e.printStackTrace();}
}

作为下一步,您可以检查构造以清理此代码。

如果我们讨论的是这样一个小程序,则或多或少是可以的。 但不需要将con、stmt和rs作为静态变量,它们可以在方法中声明。此外,您还需要重写try-catch-finally块并正确关闭资源:

Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
  // your code
} catch (SQLException e) {
  e.printStackTrace();
} finally {
  try { if (rs != null) rs.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (stmt != null) stmt.close(); } catch (Exception e) {e.printStackTrace();}
  try { if (conn != null) conn.close(); } catch (Exception e) {e.printStackTrace();}
}

作为下一步,您可以检查构造以清理此代码。

更好地使用尝试使用资源。这会自动关闭连接、语句和结果集,即使在引发异常或内部返回时也是如此

    String sql = "UPDATE users SET firstname = ? WHERE id = ?";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        stmt.setString(1, "shsh");
        stmt.setLong(2, 2);
        stmt.executeUpdate();
        System.out.println("updated successfully");
    }

    String sql = "SELECT city_name FROM agent_cities";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        try (ResultSet rs = stmt.executeQuery()) {
            while(rs.next()) {
                System.out.println(rs.getString("city_name"));
            }
        }
    }
这对于垃圾收集更好。防止rs2、rs3出现故障。允许多用户并发,就像在服务器应用程序中一样。调用该查询本身。
静态
更像是全局变量的样式。

更好地使用尝试使用资源。这会自动关闭连接、语句和结果集,即使在引发异常或内部返回时也是如此

    String sql = "UPDATE users SET firstname = ? WHERE id = ?";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        stmt.setString(1, "shsh");
        stmt.setLong(2, 2);
        stmt.executeUpdate();
        System.out.println("updated successfully");
    }

    String sql = "SELECT city_name FROM agent_cities";
    try (Connection con = bds.getConnection();
            PreparedStatement stmt = con.prepareStatement()) {
        try (ResultSet rs = stmt.executeQuery()) {
            while(rs.next()) {
                System.out.println(rs.getString("city_name"));
            }
        }
    }
这对于垃圾收集更好。防止rs2、rs3出现故障。允许多用户并发,就像在服务器应用程序中一样。调用该查询本身。
static
更像是全局变量。

您应该使用try with resources来避免任何类型的连接泄漏

下面的示例从文件中读取第一行。它使用BufferedReader实例从文件中读取数据。BufferedReader是程序完成后必须关闭的资源:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

您应该使用try with资源来避免任何类型的连接泄漏

下面的示例从文件中读取第一行。它使用BufferedReader实例从文件中读取数据。BufferedReader是程序完成后必须关闭的资源:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}


是 啊但是我有很多大型程序,我不能为每个方法签名创建新的对象,所以对于包含许多方法签名的大型程序,你的解决方案是什么呢?这取决于技术堆栈。如果java没有spring/hibernate,那么您需要一个单一的数据源(您已经有了静态BasicDataSource bds=DBConnection.getInstance().getBds();)并正确关闭资源。是的,我没有使用spring/hibernate。我正在使用Javaservlet和Maven作为Eclipse IDE的构建工具。但是我有很多大型程序,我不能为每个方法签名创建新的对象,所以对于包含许多方法签名的大型程序,你的解决方案是什么呢?这取决于技术堆栈。如果java没有spring/hibernate,那么您需要一个单一的数据源(您已经有了静态BasicDataSource bds=DBConnection.getInstance().getBds();)并正确关闭资源。是的,我没有使用spring/hibernate。我使用Java Servlets和Maven作为Eclipse IDE的构建工具。根据应用程序的复杂性,您确实不应该使用字段作为连接、语句和结果集(静态字段的味道更大)。那么还有什么更好的替代方案。当然是局部变量。这是什么原因呢?它可以防止连接使用时间过长,防止多个线程之间无意中共享连接,还可以防止其他类型的资源泄漏。这取决于应用程序的复杂性,你真的不应该在连接、语句和结果集中使用字段(静态字段的味道更大)。那么还有什么更好的选择呢?当然是局部变量。原因是什么呢?它可以防止连接存在太久,防止多线程之间无意间共享连接,它还可以防止其他类型的资源泄漏。这不是关于垃圾收集,而是关于资源清理,而“资源”是指任何不由Java垃圾收集器管理的资源。Java堆中这些对象的内存只是一个小问题。@Holger true,谢谢。事实上,我在这里找不到正确的单词。老式的C/Fortran程序员会像建议的那样使用全局变量。这个措辞很棘手,就像其他编程语言一样,任何需要分配和释放的东西都是“资源”,其中包括显式管理的内存。Java程序的思维工作