Spring之防止连接泄露的处理办法
2017-04-01 11:23
162 查看
连接泄漏
在开发过程中直接连接数据库获取连接,使用完之后不进行及时的关闭连接,连接会一直处于激活状态,就会造成连接泄露,对系统和数据库都会带来一定的压力和负担。
我们写了一个方法让主线程睡眠的形式来模拟多线程环境下的模拟
运行结果:
由于我使用的是阿里的数据源,没有找到获取空闲连接的方法
分析如下(引自网络)
解决办法:
①使用DataSourceUtils
将上述获取连接的方式改为DataSourceUtils的形式来获取连接。
然后查看运行结果:
并没有数据连接泄露。
但是这样仅仅是在配置事务的时候不会出现连接泄露,如果将事务注释之后,还是会出现一定的连接泄漏。
将配置文件中的事务注释之后,执行结果
分析如下(引自网络)
杜绝上述情况连接泄露的方式就是手动关闭连接。
②使用TransactionAwareDataSourceProxy
如果不得已要显式获取数据连接,除了使用 DataSourceUtils 获取事务上下文绑定的连接外,还可以通过 TransactionAwareDataSourceProxy 对数据源进行代理。数据源对象被代理后就具有了事务上下文感知的能力,通过代理数据源的 getConnection() 方法获取的连接和使用 DataSourceUtils.getConnection() 获取连接的效果是一样的。
将配置文件中的配置修改一下
打开事务,运行结果
没有连接泄露!
在了解数据连接泄露原理之后,触类旁通,我们可以推及其他的框架。
在开发过程中直接连接数据库获取连接,使用完之后不进行及时的关闭连接,连接会一直处于激活状态,就会造成连接泄露,对系统和数据库都会带来一定的压力和负担。
我们写了一个方法让主线程睡眠的形式来模拟多线程环境下的模拟
package com.zhu.service; import java.sql.Connection; import java.sql.SQLException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.stereotype.Service; import com.alibaba.druid.pool.DruidDataSource; @Service public class TestJdbcService { @Autowired private JdbcTemplate jdbcTemplate; public static class UserServiceRunner extends Thread{ private TestJdbcService testJdbcService; private String name; public UserServiceRunner(TestJdbcService testJdbcService,String name) { this.testJdbcService = testJdbcService; this.name = name; } @Override public void run() { testJdbcService.logon(name); } public long getThreadID() { return Thread.currentThread().getId(); } } public void logon(String name){ try { Connection connect = jdbcTemplate.getDataSource().getConnection(); String sql = "update zhu_test set last_time = ? where name = ?"; jdbcTemplate.update(sql, System.currentTimeMillis(),name); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } public static void sleep(long time){ try { Thread.sleep(time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void reportConn(DruidDataSource dataSource){ System.out.println("连接数[active]-[" + dataSource.getActiveCount()+"]"); } public static void asynclogin(TestJdbcService testJdbcService,String name){ UserServiceRunner runner = new UserServiceRunner(testJdbcService,name); System.err.println(Thread.currentThread().getName()+"ID:"+runner.getThreadID()); runner.start(); } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("file:src/main/resources/applicationContext.xml"); TestJdbcService testJdbcService = (TestJdbcService) ctx.getBean("testJdbcService"); DruidDataSource druidDataSource = (DruidDataSource) ctx.getBean("dataSource"); testJdbcService.reportConn(druidDataSource); testJdbcService.asynclogin(testJdbcService,"tom"); testJdbcService.sleep(500); testJdbcService.reportConn(druidDataSource); testJdbcService.sleep(2000); testJdbcService.reportConn(druidDataSource); testJdbcService.asynclogin(testJdbcService,"jack"); testJdbcService.sleep(500); testJdbcService.reportConn(druidDataSource); testJdbcService.sleep(2000); testJdbcService.reportConn(druidDataSource); } }
运行结果:
由于我使用的是阿里的数据源,没有找到获取空闲连接的方法
分析如下(引自网络)
解决办法:
①使用DataSourceUtils
将上述获取连接的方式改为DataSourceUtils的形式来获取连接。
public void logon(String name){ try { //Connection connect = jdbcTemplate.getDataSource().getConnection(); Connection connect = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); String sql = "update zhu_test set last_time = ? where name = ?"; jdbcTemplate.update(sql, System.currentTimeMillis(),name); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } }
然后查看运行结果:
并没有数据连接泄露。
但是这样仅仅是在配置事务的时候不会出现连接泄露,如果将事务注释之后,还是会出现一定的连接泄漏。
将配置文件中的事务注释之后,执行结果
分析如下(引自网络)
杜绝上述情况连接泄露的方式就是手动关闭连接。
②使用TransactionAwareDataSourceProxy
如果不得已要显式获取数据连接,除了使用 DataSourceUtils 获取事务上下文绑定的连接外,还可以通过 TransactionAwareDataSourceProxy 对数据源进行代理。数据源对象被代理后就具有了事务上下文感知的能力,通过代理数据源的 getConnection() 方法获取的连接和使用 DataSourceUtils.getConnection() 获取连接的效果是一样的。
将配置文件中的配置修改一下
<!-- 数据源默认将autoCommit设置为true --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://172.16.14.40:3306/zhu" p:username="zhu" p:password="zhu" /> <!-- ①对数据源进行代理--> <bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy" p:targetDataSource-ref="dataSource"/> <!-- ②直接使用数据源的代理对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSourceProxy"/>
打开事务,运行结果
没有连接泄露!
在了解数据连接泄露原理之后,触类旁通,我们可以推及其他的框架。
相关文章推荐
- 在Spring+hebernate中无法释放连接的解决办法
- "无法删除当前已连接的用户"处理办法
- Spring 的 HibernateDaoSupport 类的 getSession() 导致的连接泄露问题
- 关于用eclipse调试Desire和Desire HD机型时连接不上的处理办法
- ORACL初学(之一) oracle sqlplus异常处理: 连接后输入命令就会显示个2,处理办法
- 远程服务器连接出现"服务器连接数过多"时处理办法
- android网络编程注意事项之一:移动网络下,防止网络超时甚至连接不上,解决办法--为网络请求设置代理
- 宽带连接错误的处理办法691、623、678、645、720、721、718、734、769、619、676、815
- 宽带连接错误的处理办法
- sql server数据库在c#中连接不成功处理办法
- Spring+hibernate中不能释放tomcat连接池中连接的解决办法
- 宽带连接错误的处理办法(691、623、678、645、720、721、718、734、769、619、676、815)
- 宽带连接错误的处理办法
- JDBC连接mysql处理中文时乱码的一种解决办法
- 【转】宽带连接错误的处理办法691、623、678、645、720、721、718、734、769、619、676、815
- 基于Spring和hibernate的灵活的异常处理办法
- 管家婆辉煌-- 连接服务器失败处理办法
- 远程桌面不能用不能连接处理办法
- ORA-06413 连接未打开的处理办法【独家办法】
- linux服务器出现大量的TIME_WAIT状态的TCP连接的处理办法