java 数据库连接 释放_java - 数据库连接池耗尽 - Java - 堆栈内存溢出

timeout变量似乎不对应于连接空闲的时间,而是对应于池等待返回新连接或抛出异常的时间(我看了一下这个源代码 ,不知道是不是已是最新)。 我认为跟踪“空闲”连接是相当困难的,因为在这种情况下“空闲”真正意味着什么? 您可能希望获得连接以供以后使用。 所以我想说连接池知道你完成连接的唯一安全方法就是调用close() 。

如果你担心开发团队忘记在他们的代码中调用close() ,有一种技术我在下面描述并且我过去曾经使用过(在我的例子中我们想要跟踪未闭合的InputStream但概念是相同)。

免责声明:

我假设连接仅在单个请求期间使用,并且在连续请求期间不跨越。 在后一种情况下,您无法使用下面的解决方案。

您的连接池实现似乎已经使用了与我在下面描述的技术类似的技术(即它已经包装了连接),所以我不可能知道这是否适用于您的情况。 我没有测试下面的代码,我只是用它来描述这个概念。

请仅在您的开发环境中使用它。 在生产中,您应该确信您的代码已经过测试并且行为正确。

如上所述,主要思想是:我们有一个中心位置(连接池),我们从中获取资源(连接),我们希望跟踪我们的代码是否释放了这些资源。 我们可以使用一个Web Filter ,它使用一个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();

}

}

...

}

为了使Tracker能够跟踪连接,每次使用getConnection()获取连接时以及每次使用close()调用关闭连接时都需要通知它。 为了能够以对代码的其余部分透明的方式执行此操作,我们需要包装ConnectionPool和返回的Connection对象。 您的代码应该返回新的TrackingConnectionPool而不是原始池(我假设访问连接池的方式是在一个地方)。 这个新池将依次包装它提供的每个Connection ,作为TrackableConnection 。 TrackableConnection是知道如何在创建和关闭时通知我们的Tracker的对象。

当您在请求结束时调用Tracker.stop()时,它将报告尚未调用close()所有连接。 由于这是一个按请求操作,您将只识别错误操作(即在“创建新产品”功能期间),然后希望您能够跟踪那些保留打开连接并修复它们的查询。

您可以在下面找到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 = new ThreadLocal() {

@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 monitoredResources = new HashMap();

// 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 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);

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spark DAGScheduler、TaskSchedule、Executor执行task源码分析

摘要 spark的调度一直是我想搞清楚的东西,以及有向无环图的生成过程、task的调度、rdd的延迟执行是怎么发生的和如何完成的,还要就是RDD的compute都是在executor的哪个阶段调用和执行我们定义的函数的。这些都非常的基础和困难。花一段时间终于弄白了其中…

一个“老”程序员的思考

本文是一位40岁老程序员对职业生涯的思考,建议多学习接触新事物,将精力投入到衰竭期比较长的知识领域,这些都是很有建设性的。下面是大意译文: 我是一个程序员,几个月前刚过完害羞的四十岁生日。这是一个星期六的早晨…

python socketio_python3--socketIO_client 摸索怕坑指南

前言:websocket和socketIO是全然不同的两个东西,websocket的话 使用自带ws的库就可以完成一些功能,但是socketIO属于sw的另外一块内容工作中遇到了一个监控socketIO传输的聊天信息监控的需求.研究了一阵 话不多说 上代码!from socketIO_client import SocketIO, BaseNamespacei…

java正则表达式非贪婪_正则表达式中的贪婪与非贪婪匹配模式

1.首先看看下面的例子:try{str"abcdefgabcdefghijkl";re1str.match(/[\W\w]?/ig);alert("非贪婪模式:\r\n\r\n1:"re1[0]"\r\n2:"re1[1]);re1str.match(/[\W\w]/ig);alert("贪婪模…

python编程运算符号-Python中的逻辑运算符

参考资料:http://blog.csdn.net/sasoritattoo/article/details/12451359 一、逻辑判断词not 1.在python中not是逻辑判断词,用于布尔型True和False,not True为False,not False为True,以下是几个常用的not的用法&#xf…

代码实现tan graph model for classification_自定义 Estimator 实现(以BERT为例)

本文将主要介绍tensorflow 的Estimator 这个高级API,它的主要作用就是提出一个高级范式(paradigm),将模型的训练,验证,预测,以及保存规范起来,免去了tensorflow的Session.run 的操作…

Linux查看文件内容

cat 一次性将文件内容全部输出到控制台 more 可以翻页查看 空格:下翻一页 b:上翻一页 q:退出 less 可以翻页查看 空格:下翻一页 b:上翻一页 q:退出 向上键:上翻一行 向下键&#xff1…

刷新页面微信二维码图片随机换,点击按钮自动复制对应微信号

<div style"text-align: center;"> <p style"font-size: 18px;color: rgb(255, 79, 121);">添加微信号</p> <span style"font-size: 18px;margin-left: 10%;" id"cod">jyl88jimei</span><br /> &…

SecureCRT向多个tab窗口发命令

可以利用SecureCRT的 Chat Windows选项Send chat to all tabs来同时在服务器上执行相同的命令&#xff0c;具体步骤如下&#xff1a; 一、首先在SecureCRT里同时打开多个服务器session 二、选择菜单栏View -->Chat Windows 对号&#xff0c;此时所有服务器连接下方应该有个…

英雄联盟怎么解除小窗口_英雄联盟手游怎么加好友_英雄联盟手游怎么加好友一起玩_资讯...

英雄联盟手游是腾讯联合英雄联盟开发商拳头开发的英雄联盟手游。不仅能够高度还原端游的经典操作和竞技体验&#xff0c;也具有非常多创新的元素&#xff0c;对于英雄联盟的全球生态布局具有重要意义。英雄联盟手游游戏中有非常多的英雄可以供玩家选择&#xff0c;并且拥有排位…

jfinal mysql 配置文件_JFinal 如何将操作日志存入到数据库中

展开全部操作日志, 也分粗细颗粒.比如常见的 配置JFinal的Handler, 配置LogHandler的处理器&#xff0c;Handler可以接管所有web请求, 这里可以做粗颗粒的处理, 对每一个请62616964757a686964616fe59b9ee7ad9431333365653839求做入库处理, 如果访问量大时, 入库操作做列队处理就…

快速入门python_一天快速入门 Python

Python 是由Guido Van Rossum在 90 年代早期设计&#xff0c;现在是最常用的编程语言之一。特别是人工智能的火热&#xff0c;再加之它的语法简洁且优美&#xff0c;实乃初学者入门AI必备的编程语言。作者 | yuquanle责编 | 屠敏Python基本语法标识符第一个字符必须是英文字母或…

Sonar与jenkins集成

2019独角兽企业重金招聘Python工程师标准>>> 参考文档&#xff1a;http://blog.csdn.net/kefengwang/article/details/54377055 一.下载&#xff1a;wget https://fossies.org/linux/misc/sonarqube-7.0.zip 二.配置sonar.properties ## sudo vim /opt/sonarqube-6.…

python变量和常量_5、python的变量和常量

今天看看python的变量和常量&#xff0c;这是python中最基本的两个概念。首先先说一下解释器执行Python的过程&#xff1a; python3 C:\test.py1. 启动python解释器(内存中)2. 将C:\test.py内容从硬盘读入内存(这一步与文本编辑器是一样的)3. 执行读入内存的代码如果想要永久…

eplan连接定义点不显示_EPLAN电气图实例--控制柜(控制面板)

EPLAN电气图实例--控制柜(控制面板)上期回顾(上期主要画了硬件的布局图)&#xff1a;这期主要画一个控制面板控制柜布局1.0 上期主要做了一个长方形的结构板&#xff0c;里面插入了一个结构盒&#xff0c;然后放置一个HMI的宏(这里是KTP1000&#xff0c;在官网随便找下就行了)&…

virtualbox安装android6.0并设置分辨率为1920x1080x32

下载安装&#xff1a;https://www.cnblogs.com/wynn0123/p/6288344.html 这里我做的是下载android6.0-64bit&#xff0c;然后文件系统只支持ext4 安装完成之后我的虚拟机名称是Android6.0 设置分辨率为1920x1080x32&#xff1a;https://my.oschina.net/xldc/blog/290155 首先&a…

python中装饰器修复技术_python3之装饰器修复技术@wraps

普通函数def f():"""这是一个用来测试装饰器修复技术的函数"""print("哈哈哈")if __name__ __main__:print("执行的函数名:", f.__name__)print("函数的注释:", f.__doc__)# 打印结果执行的函数名: f函数的注释:…

markdown 语法_markdown特殊语法之上下标

markdown特殊语法之上下标​markdown的基本语法很简单&#xff0c;百度一下就可以了&#xff0c;有空的话我再转载一些过来。我想的是平常其实需要用到的一些输入技巧&#xff0c;特殊用法或者扩展语法&#xff0c;还有一些难点倒是要记录学习一下。在写作的时候&#xff0c;大…

oracle安装向导卡住了_JDK 8 的安装与配置

一、安装环节1. 打开网页https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html2.找到对象的版本 尽量从官网下载(官网可能会比较慢&#xff0c;也可以通过浏览器输入jdk版本号进行下载)官网下载需要注册一个账号3.双击下载的 exe,如 jdk-8u131-windows…

Error contacting service. It is probably not running.

安装完zookeeper集群后&#xff0c; [rootzk1 data]# zkServer.sh start JMX enabled by default Using config: /application/zookeeper-3.3.6/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [rootzk1 data]# zkServer.sh status JMX enabled by default Using config…