您的位置:首页 > 编程语言 > Java开发

Spring之防止连接泄露的处理办法

2017-04-01 11:23 162 查看
连接泄漏

在开发过程中直接连接数据库获取连接,使用完之后不进行及时的关闭连接,连接会一直处于激活状态,就会造成连接泄露,对系统和数据库都会带来一定的压力和负担。

我们写了一个方法让主线程睡眠的形式来模拟多线程环境下的模拟

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"/>


打开事务,运行结果



没有连接泄露!

在了解数据连接泄露原理之后,触类旁通,我们可以推及其他的框架。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: