如何在退出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 { ... }
块,同时仍然关闭资源。
所以,这里有一些背景信息:我目前在一家提供 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 { ... }
块,同时仍然关闭资源。