我们的一个遗留应用程序中存在数据库连接泄漏,我将其跟踪到这个小宝石。从调试开始,我可以看到为多个线程返回相同的逻辑连接(不好!)。但我很难理解为什么会这样。
我们正在使用ojdbc6驱动程序,在具有连接池的WebLogic数据源上进行设置。
产生问题的代码
public class MyDummyDaoUtil {
//note: this is a public field in a singleton (not a static field though...)
public Connection conn;
private MyDummyDaoUtil() {
}
public static MyDummyDaoUtil getInstance() {
if (instance == null) {
instance = new MyDummyDaoUtil();
}
return instance;
}
private DataSource getDataSource(final String dsName)
throws NamingException {
return ServiceLocator.getInstance().getDataSource(dsName);
}
public static Connection getConnection(final String source)
throws NamingException {
return MyDummyDaoUtil.getInstance().getDBConnection(source);
}
private Connection getDBConnection(final String source)
throws NamingException {
//the same logical connection is produced by the data source or something else happening?
conn = getDataSource(source).getConnection();
conn.setAutoCommit(false);
return conn;
}
}
更新了修复程序
public class MyDummyDaoUtil {
private MyDummyDaoUtil() {
}
public static MyDummyDaoUtil getInstance() {
if (instance == null) {
instance = new MyDummyDaoUtil();
}
return instance;
}
private DataSource getDataSource(final String dsName)
throws NamingException {
return ServiceLocator.getInstance().getDataSource(dsName);
}
public static Connection getConnection(final String source)
throws NamingException {
return MyDummyDaoUtil.getInstance().getDBConnection(source);
}
private Connection getDBConnection(final String source)
throws NamingException {
Connection conn = getDataSource(source).getConnection();
conn.setAutoCommit(false);
return conn;
}
}
修复摘要
答案 0 :(得分:0)
您正在使用单例模式,并且在多线程环境中使用时必须以同步方式处理对象实例化。
尝试任何一个选项:
使用getInstance()
同步方法
public static synchronized MyDummyDaoUtil getInstance() {
if (instance == null) {
instance = new MyDummyDaoUtil();
}
return instance;
}
实例化急切
private static MyDummyDaoUtil instance = new MyDummyDaoUtil();
public static MyDummyDaoUtil getInstance() {
return instance;
}
使用双重检查锁定机制
public static MyDummyDaoUtil getInstance() {
if (instance == null) {
synchronized(MyDummyDaoUtil.class){
if (instance == null) {
instance = new MyDummyDaoUtil();
}
}
}
return instance;
}
注意:请勿忘记关闭Connection。
答案 1 :(得分:0)
假设您要问的是“为什么更改此代码会修复getDBConnection在多个线程上返回相同对象的问题”...
您正在使用可变状态(MyDummyDaoUtil.conn)。请考虑以下情形 - 两个线程(A和B)同时调用原始函数:
private Connection getDBConnection(final String source)
throws NamingException {
conn = getDataSource(source).getConnection(); //line 1
conn.setAutoCommit(false); //line 2
return conn; //line 3
}
这里有很多可能的序列,但这里有一个有问题的示例:
connectionA
),MyDummyDaoUtil.conn
设置为connectionA
。connectionB
),MyDummyDaoUtil.conn
设置为connectionB
。conn
现在为connectionB
,因此导致connectionB
上的自动提交设置为false。connectionB
(从另一个线程创建的那个)。connectionB
上设置自动提交为false(这是一个无操作,因为线程A在事故中已经这样做了)connectionB
。问题是MyDummyDaoUtil.conn
,因为它是一个单例成员变量,所以在两个线程中引用相同的变量。在你的第二个例子中,有一个局部变量的事实意味着每次调用函数都有一个单独的变量,因此你不会在调用之间产生交叉污染。