连接未被释放到多线程程序中的池
Connections not being released to pool in multithreaded program
大家好
出于某种原因,我的连接没有被释放。我在一天的大部分时间里都在处理这个问题,所以现在我希望你们中的一个能帮助我。
DataSource 位于 Swagger jaxws 服务器中。因此,在每次请求时,我都会从池中检索一个连接。这是我的数据源 class,其中 return 是来自池的连接:
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp2.BasicDataSource;
/**
*
* @author Lagoni
*/
public class DataSource {
private static DataSource datasource;
private BasicDataSource ds;
private DataSource() throws IOException, SQLException, PropertyVetoException {
ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUsername("username");
ds.setPassword("pw");
ds.setUrl("jdbc:postgresql://host" + 5432 + "/db");
ds.setMaxWaitMillis(20000); //wait 10 seconds to get new connection
ds.setMaxTotal(5);
ds.setMaxIdle(5);
ds.setTestWhileIdle(true);
ds.setTestOnReturn(true);
ds.setTimeBetweenEvictionRunsMillis(1000);
ds.setSoftMinEvictableIdleTimeMillis(100);
ds.setMinEvictableIdleTimeMillis(10);
ds.setMaxConnLifetimeMillis(1000*60*10);
}
public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
if (datasource == null) {
datasource = new DataSource();
}
return datasource;
}
public Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
对于需要使用数据库连接的每个函数,通过调用检索它:
Connection con = DataSource.getInstance().getConnection();
这就是我得到 "Cannot get a connection, pool error Timeout waiting for idle object" 的地方。我确保每个线程只使用一个连接。因此,如果函数需要多次调用数据库,它会重用 con 变量。
我得出的结论是,我永远不应该调用 con.close(),因为它会 return 到池的空连接。当一个函数完成连接时,将调用以下函数:
resultSet.close();
statement.close();
在连接被声明为空闲之前,我有没有忘记做些什么?或者我只是没有正确实现连接池?我应该尝试使用另一种泳池还是?
我正在使用以下 Maven 依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
</dependency>
编辑 1
这是一个解决方案吗?
try(Connection con = DataSource.getInstance().getConnection()){
UploadedFile file = new FileServerImplementation().uploadFile(fileType, fileName, folderId, projectId, tokenString, fileInputStream, con);
if(file != null){
return Response.ok().entity(file).build();
}
}
此处的 uploadFile 方法如下:
public UploadedFile uploadFile(String fileType, String fileName, Long folderId, Long projectId, String tokenString, InputStream fileInputStream, Connection con) throws SQLException, IOException, PropertyVetoException{
IOController ioController = new IOController();
DatabaseController controller = DatabaseController.getInstance();
UploadedFile file = null;
if(ioController.uploadFile(fileType, fileName, controller.getFolderPath(folderId, con), projectId, fileInputStream)){
file = controller.uploadFile(fileType, fileName, folderId, projectId, con);
}else{
System.out.println("Error uploading " + fileName + " to folder!");
}
return file;
}
IOController 将文件保存到磁盘上,然后 uploadFile 方法将一些数据上传到数据库。或者我应该每次调用 DatabaseController 中的方法 class 从池中获取新连接?
解决方案
我最终使用编辑 1 作为一种方法。我只需要确保在不再次关闭它们的情况下没有创建不必要的连接。
使用连接池时,您需要close
将连接释放到池中以供重新使用。 不要保持线程中的连接。
大家好
出于某种原因,我的连接没有被释放。我在一天的大部分时间里都在处理这个问题,所以现在我希望你们中的一个能帮助我。
DataSource 位于 Swagger jaxws 服务器中。因此,在每次请求时,我都会从池中检索一个连接。这是我的数据源 class,其中 return 是来自池的连接:
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp2.BasicDataSource;
/**
*
* @author Lagoni
*/
public class DataSource {
private static DataSource datasource;
private BasicDataSource ds;
private DataSource() throws IOException, SQLException, PropertyVetoException {
ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUsername("username");
ds.setPassword("pw");
ds.setUrl("jdbc:postgresql://host" + 5432 + "/db");
ds.setMaxWaitMillis(20000); //wait 10 seconds to get new connection
ds.setMaxTotal(5);
ds.setMaxIdle(5);
ds.setTestWhileIdle(true);
ds.setTestOnReturn(true);
ds.setTimeBetweenEvictionRunsMillis(1000);
ds.setSoftMinEvictableIdleTimeMillis(100);
ds.setMinEvictableIdleTimeMillis(10);
ds.setMaxConnLifetimeMillis(1000*60*10);
}
public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
if (datasource == null) {
datasource = new DataSource();
}
return datasource;
}
public Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
对于需要使用数据库连接的每个函数,通过调用检索它:
Connection con = DataSource.getInstance().getConnection();
这就是我得到 "Cannot get a connection, pool error Timeout waiting for idle object" 的地方。我确保每个线程只使用一个连接。因此,如果函数需要多次调用数据库,它会重用 con 变量。
我得出的结论是,我永远不应该调用 con.close(),因为它会 return 到池的空连接。当一个函数完成连接时,将调用以下函数:
resultSet.close();
statement.close();
在连接被声明为空闲之前,我有没有忘记做些什么?或者我只是没有正确实现连接池?我应该尝试使用另一种泳池还是?
我正在使用以下 Maven 依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.4</version>
</dependency>
编辑 1
这是一个解决方案吗?
try(Connection con = DataSource.getInstance().getConnection()){
UploadedFile file = new FileServerImplementation().uploadFile(fileType, fileName, folderId, projectId, tokenString, fileInputStream, con);
if(file != null){
return Response.ok().entity(file).build();
}
}
此处的 uploadFile 方法如下:
public UploadedFile uploadFile(String fileType, String fileName, Long folderId, Long projectId, String tokenString, InputStream fileInputStream, Connection con) throws SQLException, IOException, PropertyVetoException{
IOController ioController = new IOController();
DatabaseController controller = DatabaseController.getInstance();
UploadedFile file = null;
if(ioController.uploadFile(fileType, fileName, controller.getFolderPath(folderId, con), projectId, fileInputStream)){
file = controller.uploadFile(fileType, fileName, folderId, projectId, con);
}else{
System.out.println("Error uploading " + fileName + " to folder!");
}
return file;
}
IOController 将文件保存到磁盘上,然后 uploadFile 方法将一些数据上传到数据库。或者我应该每次调用 DatabaseController 中的方法 class 从池中获取新连接?
解决方案
我最终使用编辑 1 作为一种方法。我只需要确保在不再次关闭它们的情况下没有创建不必要的连接。
使用连接池时,您需要close
将连接释放到池中以供重新使用。 不要保持线程中的连接。