我在应用程序中使用连接池(snaq.db.ConnectionPool)。连接池的初始化方式如下:
String dburl = propertyUtil.getProperty("dburl");
String dbuserName = propertyUtil.getProperty("dbuserName");
String dbpassword = propertyUtil.getProperty("dbpassword");
String dbclass = propertyUtil.getProperty("dbclass");
String dbpoolName = propertyUtil.getProperty("dbpoolName");
int dbminPool = Integer.parseInt(propertyUtil.getProperty("dbminPool"));
int dbmaxPool = Integer.parseInt(propertyUtil.getProperty("dbmaxPool"));
int dbmaxSize = Integer.parseInt(propertyUtil.getProperty("dbmaxSize"));
long dbidletimeout = Long.parseLong(propertyUtil.getProperty("dbidletimeout"));
Class.forName(dbclass).newInstance();
ConnectionPool moPool = new ConnectionPool(dbpoolName, dbminPool, dbmaxPool, dbmaxSize,
dbidletimeout, dburl, dbuserName, dbpassword);
使用的DB池值是:
dbminPool=5
dbmaxPool=30
dbmaxSize=30
dbclass=org.postgresql.Driver
dbidletimeout=25
我的应用程序在某处泄漏连接(连接未被释放),因此连接池已耗尽。我现在已经修好了密码。
空闲超时后连接不应该关闭吗?如果这不是正确的假设,有没有办法关闭打开的空闲连接(仅通过java代码)?
连接池的全部意义在于让连接池为您处理所有这些事情。
空闲
或在用
连接的映射
IN-USE
:如果应用程序正在引用一个连接对象,它将被池放入IN-USE map
IDLE
:如果一个连接对象没有被应用程序引用/或关闭
,它将被池放入IDLE map
空闲
连接被放入在用映射
idle pool
没有任何可用条目,pool被迫创建更多条目
正在使用
打开的空闲连接
,您可以通过代码关闭这些连接
在修复代码中的连接泄漏时,您已经尽了最大努力。
您可以强制
释放池并重新创建一个池。但是你必须小心,因为正在使用的现有连接可能会在执行任务时受到影响。
你没有发布完整的代码,所以我假设你没有关闭连接。仍然需要关闭从池中获取的连接对象,就像不使用池时一样。关闭连接使池可以重新发送给另一个调用方。如果您未能做到这一点,您最终将消耗池中所有可用的连接。池中陈旧的连接清理器不是清理连接的最佳场所。就像你妈妈告诉你的,收拾完东西后把它们收起来。
try {
conn = moPool.getConnection(timeout);
if (conn != null)
// do something
} catch (Exception e) {
// deal with me
} finally {
try {
conn.close();
} catch (Exception e) {
// maybe deal with me
}
}
timeout
变量似乎不对应于连接空闲的时间,而是对应于池可以等待多长时间来返回新连接或抛出异常(我看了一下这个源代码,不知道它是否是最新的)。我认为跟踪“空闲”连接会相当困难,因为在这种情况下“空闲”的真正含义是什么?您可能希望获得一个连接以供以后使用。所以我想说连接池知道您完成连接的唯一安全方法是调用关闭()
。
如果您担心开发团队忘记在他们的代码中调用关闭()
,我在下面描述了一种技术,并且我过去曾使用过(在我的案例中,我们希望跟踪未关闭的InputStream
s,但概念是相同的)。
免责声明:
综上所述,其主要思想是:我们有一个中心位置(连接池),从中获取资源(连接),我们希望跟踪这些资源是否由我们的代码释放。我们可以使用一个web过滤器
,它使用一个ThreadLocal
对象来跟踪请求期间使用的连接。我将这个类命名为TrackingFilter
,跟踪资源的对象是Tracker
类。
public class TrackingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Tracker.start();
try {
chain.doFilter(request, response);
} finally {
Tracker.stop();
}
}
...
}
为了让跟踪器能够跟踪连接,每次使用
getConnection()
获取连接时,以及每次使用close()
调用关闭连接时,都需要通知跟踪器。为了以对其余代码透明的方式实现这一点,我们需要包装ConnectionPool
和返回的Connection
对象。您的代码应该返回新的TrackingConnectionPool
,而不是原始池(我假设访问连接池的方法是在一个地方)。这个新池将依次包装它提供的每个连接
,作为可跟踪连接
。TrackableConnection
是一个对象,它知道如何在创建和关闭时通知我们的跟踪器。
当您在请求末尾调用
Tracker.stop()
时,它将报告尚未调用关闭()
的任何连接。由于这是按请求操作,您将仅识别错误操作(即在“创建新产品”功能期间),然后希望您能够跟踪那些留下打开连接并修复它们的查询。
在下面,您可以找到
TrackingConnectionPool
、TrackableConnection
和Tracker
类的代码和注释。为了简洁起见,省略了委托方法。我希望这能有所帮助。
注意:对于包装器,请使用自动IDE功能(如Eclipse的“生成委托方法”),否则这将是一项耗时且容易出错的任务。
//------------- Pool Creation
ConnectionPool original = new ConnectionPool(String dbpoolName, ...);
TrackingConnectionPool trackingCP = new TrackingConnectionPool(original);
// ... or without creating the ConnectionPool yourself
TrackingConnectionPool trackingCP = new TrackingConnectionPool(dbpoolName, ...);
// store the reference to the trackingCP instead of the original
//------------- TrackingConnectionPool
public class TrackingConnectionPool extends ConnectionPool {
private ConnectionPool originalPool; // reference to the original pool
// Wrap all available ConnectionPool constructors like this
public TrackingConnectionPool(String dbpoolName, ...) {
originalPool = new ConnectionPool(dbpoolName, ...);
}
// ... or use this convenient constructor after you create a pool manually
public TrackingConnectionPool(ConnectionPool pool) {
this.originalPool = pool;
}
@Override
public Connection getConnection() throws SQLException {
Connection con = originalPool.getConnection();
return new TrackableConnection(con); // wrap the connections with our own wrapper
}
@Override
public Connection getConnection(long timeout) throws SQLException {
Connection con = originalPool.getConnection(timeout);
return new TrackableConnection(con); // wrap the connections with our own wrapper
}
// for all the rest public methods of ConnectionPool and its parent just delegate to the original
@Override
public void setCaching(boolean b) {
originalPool.setCaching(b);
}
...
}
//------------- TrackableConnection
public class TrackableConnection implements Connection, Tracker.Trackable {
private Connection originalConnection;
private boolean released = false;
public TrackableConnection(Connection con) {
this.originalConnection = con;
Tracker.resourceAquired(this); // notify tracker that this resource is aquired
}
// Trackable interface
@Override
public boolean isReleased() {
return this.released;
}
// Note: this method will be called by Tracker class (if needed). Do not invoke manually
@Override
public void release() {
if (!released) {
try {
// attempt to close the connection
originalConnection.close();
this.released = true;
} catch(SQLException e) {
throw new RuntimeException(e);
}
}
}
// Connection interface
@Override
public void close() throws SQLException {
originalConnection.close();
this.released = true;
Tracker.resourceReleased(this); // notify tracker that this resource is "released"
}
// rest of the methods just delegate to the original connection
@Override
public Statement createStatement() throws SQLException {
return originalConnection.createStatement();
}
....
}
//------------- Tracker
public class Tracker {
// Create a single object per thread
private static final ThreadLocal<Tracker> _tracker = new ThreadLocal<Tracker>() {
@Override
protected Tracker initialValue() {
return new Tracker();
};
};
public interface Trackable {
boolean isReleased();
void release();
}
// Stores all the resources that are used during the thread.
// When a resource is used a call should be made to resourceAquired()
// Similarly when we are done with the resource a call should be made to resourceReleased()
private Map<Trackable, Trackable> monitoredResources = new HashMap<Trackable, Trackable>();
// Call this at the start of each thread. It is important to clear the map
// because you can't know if the server reuses this thread
public static void start() {
Tracker monitor = _tracker.get();
monitor.monitoredResources.clear();
}
// Call this at the end of each thread. If all resources have been released
// the map should be empty. If it isn't then someone, somewhere forgot to release the resource
// A warning is issued and the resource is released.
public static void stop() {
Tracker monitor = _tracker.get();
if ( !monitor.monitoredResources.isEmpty() ) {
// there are resources that have not been released. Issue a warning and release each one of them
for (Iterator<Trackable> it = monitor.monitoredResources.keySet().iterator(); it.hasNext();) {
Trackable resource = it.next();
if (!resource.isReleased()) {
System.out.println("WARNING: resource " + resource + " has not been released. Releasing it now.");
resource.release();
} else {
System.out.println("Trackable " + resource
+ " is released but is still under monitoring. Perhaps you forgot to call resourceReleased()?");
}
}
monitor.monitoredResources.clear();
}
}
// Call this when a new resource is acquired i.e. you a get a connection from the pool
public static void resourceAquired(Trackable resource) {
Tracker monitor = _tracker.get();
monitor.monitoredResources.put(resource, resource);
}
// Call this when the resource is released
public static void resourceReleased(Trackable resource) {
Tracker monitor = _tracker.get();
monitor.monitoredResources.remove(resource);
}
}
我在项目中使用ApacheTomcat JDBC连接池。我很困惑,因为在重负下,我一直看到以下错误: 我的期望是,使用池,新连接的请求将被保留在队列中,直到连接可用。相反,当池达到容量时,请求似乎会被拒绝。这种行为可以改变吗? 谢谢, 达尔 这是我的池配置:
我有使用hikari池创建连接池的Spring启动应用程序。我们正在使用postgres sql用于db。当我以低qps命中系统时,请求需要大约200毫秒来执行。当部署一个pod并且qps为15时,事情保持良好状态。但是一旦我将qps增加到20,请求就开始需要大约10秒来处理,连接池变空(java.sql.SQLTransientConntion异常:菲尼克斯-连接不可用,请求在30183毫秒后超
我有一个Spring启动,Hibernate使用java应用程序。我部署它在一个jetty webserver与多个实例.如果我有太多(大于10)很多实例我得到 许多连接(10x实例)显示为空闲 ps: 实例的Hikari跟踪日志: 设置 没有记录任何有趣的事情。我认为这看起来很有趣-连接不可用 有什么办法可以调试这个吗?我也在java 7上,所以hikari 2.4.7
问题内容: 我在GlassFish上有一个Java-JSF Web应用程序,我想在其中使用连接池。因此,我创建了一个有范围的Bean,可与其他Bean的实例一起使用: 这样,连接池很快就会被填满。在“ db-related”视图中进行几次导航后,应用程序将停止以下操作: RAR5117:无法从连接池[mysql_testPool]获取/创建连接。原因:使用中的连接等于最大池大小和已过期的最大等待时
在为了使用多线程而修改了一个服务方法之后,我发现如果不止一个用户多次尝试请求页面(并调用服务方法),服务器就会抛出“无法连接,池耗尽”异常。让我提供一个我的服务类的例子。 我已经在这个问题上挣扎了一个多星期,我找不到解决方案。我不太明白Grails如何与会话、连接和事务一起工作。我的猜测是跟随。当调用ConvertDocumentToJSON时,它从池中获取连接(4个用户,每个用户25个线程=10
null null 额外信息:没有其他异常抛出,我知道。所有其他数据都被正确地检索。派人帮忙。 更新:我做了一些更多的实验:这个应用程序使用了另一个dao,我之前没有提到,因为我忘了。它的工作方式几乎相同,只是连接到一个不同的数据库,所以它有一个单独的配置。它还利用了JdbcNamedTemplate和@Qualifier来选择正确的模板。 现在,我发现,使一个或另一个DAO失效将不再吃连接。所以