我已经实现了一个连接池。一切都很好。现在,如果客户端借用了一个连接,甚至将其返回到池中,但客户端还保留了该连接的引用。现在,如果池返回相同的连接到另一个客户端;这将导致多人使用相同的连接。
我怎样才能避免这种情况?
我已经实现了一个连接池。一切都很好。现在,如果客户端借用了一个连接,甚至将其返回到池中,但客户端还保留了该连接的引用。现在,如果池返回相同的连接到另一个客户端;这将导致多人使用相同的连接。
我怎样才能避免这种情况?
不要返回底层连接对象,而是另一个包装它的对象。在该对象中(使用某种私有属性)存储该对象的状态;它是否仍然可以使用,或者它是否已通过返回池或其他一些条件(如超时)而失效)。然后,您可以拦截任何尝试使用它的方法调用并检查其状态。如果不再可用,则抛出异常。
包装的连接对象也需要是私有的,这样客户端就不能直接访问它。
每个客户端都有一个包装器,但两个或多个包装器可以共享底层连接对象。但是因为您是为每个客户端存储状态,所以一次只有一个客户端可以使用该对象。
编辑以包含一个未经测试的示例 - 现在显示我的方法存在一个大问题。
假设您要返回实现 java.sql.Connection 的内容,则可以返回以下类的实例。
package same.package.as.your.pool; // so your pool has access to set isValidConnection
import java.sql.Connection;
class MyConnection implements Connection {
private Connection actualConnection;
private boolean isValidConnection = false;
MyConnection(Connection conn) {
// package acccess for pool class to create connection
actualConnection = conn;
isValidConnection = true;
}
public boolean getIsValidConnection() {
return isValidConnection;
}
void setIsValidConnection(boolean isValid) {
// pool class can call this to invalidate when returned to pool or timed out
isValidConnection = isValid;
}
// intercept java.sql.Connection methods, checking if connection is still valid first
// for example
PreparedStatement prepareStatement(String sql) {
if (! isValidConnection) {
// WHAT TO DO HERE?
}
return actualConnection.prepareStatement(sql);
}
// ... and the rest
第一个大问题是 - 理想情况下,当连接不再有效时,您会从 prepareStatement 等方法中抛出异常,因为它已返回到池中。但是因为您受到原始接口的捕获异常的约束(在这种情况下,抛出 SQLException),您要么需要抛出 SQLException(yuk,它不是真正的 SQLException),要么需要抛出未捕获的异常(yuk - 客户端代码可能想要捕获池连接不再有效的情况)或其他情况:-)
上述代码的另外两个问题 - 用于保护仅对池代码可用的方法的包访问不是很健壮。也许您可以将 MyConnection 代码创建为池代码中的某种内部类。最后,必须重写所有java.sql.Connection 接口会很痛苦。
}