如何在退出class的任何方法时自动释放连接?

How to release a connection automatically when exiting any method of a class?

所以,这里有一些背景信息:我目前在一家提供 SaaS 的公司工作,我的工作涉及使用 JDBC 编写方法来检索和处理数据库中的数据。这是问题所在,大多数方法都带有特定的模式来管理连接:

public Object someMethod(Object... parameters) throws MyCompanyException{
    try{
        Connection con = ConnectionPool.getConnection();
        con.setAutoCommit(false);

        // do something here

        con.commit();
        con.setAutoCommit(true);
    }
    catch(SomeException1 e){
        con.rollback();
        throw new MyCompanyException(e);
    } 
    catch(SomeException2 e){
        con.rollback();
        throw new MyCompanyException(e);
    }
    // repeat until all exception are catched and handled
    finally {
        ConnectionPool.freeConnection(con);
    }
    // return something if the method is not void
}

公司已经把所有的方法都这样做了,这样一旦发现异常,方法就会回滚所有的修改,连接也会尽快释放。然而,有时我们中的一些人可能会在编码时忘记做一些常规的事情,例如在发生错误时释放连接或回滚,并且在我们的客户投诉之前这种错误不太容易被发现。所以我决定让这些例行的事情自动完成,即使它没有在方法中声明。对于连接的发起和建立,可以很容易地使用构造函数来完成。

public abstract SomeAbstractClass {
    protected Connection con;
    public SomeAbstractClass() {
        con = CoolectionPool.getConnection();
        con.setAutoCommit(false);
    }
}

但真正的问题是在完成该方法后立即自动释放连接。我考虑过使用 finalize() 来这样做,但这不是我要找的,因为 finalize() 被 GC 调用,这意味着它可能不会在方法完成时完成我的对象,并且即使永远不会引用该对象。 finalize() 仅在 JVM 确实 运行 内存不足时才调用。

有没有办法在该方法完成工作后立即自动释放我的连接?

您可以向 ConnectionPool class 添加一个方法,例如:

public <T> T execute(Function<Connection, T> query,
                      T defaultValue,
                      Object... parameters) {
  try {
    Connection con = ConnectionPool.getConnection();
    con.setAutoCommit(false);

    Object result = query.apply(conn);
    con.commit();
    con.setAutoCommit(true);
    return result;
  } catch(SomeException1 e) {
    con.rollback();
    throw new MyCompanyException(e);
  }
  //etc.
  finally {
    ConnectionPool.freeConnection(con);
  }
  return defaultValue;
}

然后您从其余代码中调用它:

public Object someMethod(Object... parameters) throws MyCompanyException {
  return ConnectionPool.execute(
    con -> { ... }, //use the connection and return something
    null, //default value
    parameters
  );
}

执行此操作的标准方法之一是使用 AOP。您可以查看 Spring 框架,了解它如何处理 JDBC 交易和连接并使用 MethodInterceptor 管理它们。我的建议是在你的项目中使用 Spring 而不是重新发明轮子。

MethodInterceptor 背后的想法是在调用 JDBC 相关方法之前添加创建和打开连接的代码,将连接放入本地线程,以便您的方法可以获得连接以建立 SQL调用,方法执行完毕后关闭。

使用"try with resources"。这是一种编程模式,您可以编写一个典型的 try - catch 块,如果出现任何问题或您退出它,资源将关闭。

try (Connection con = ConnectionPool.getConnection()) {
   con.doStuff(...);
}
// at here Connection con is closed.

它的工作原理是 Connection 扩展 Closeable,如果 try 语句的 "resource acquisition" 部分中的任何 class 实现 Closeable,则对象的 close() 方法将在控制传递出 try / catch 块之前被调用。

这避免了在许多情况下使用 finally { ... } 的需要,并且实际上比大多数手写的 finally { ... } 块更安全,因为它还适应 catch { ... }finally { ... } 块,同时仍然关闭资源。