javadbcp2多线程连接访问
java dbcp2 multithreaded connection access
我非常熟悉在 tomcat 上使用连接池并且已经使用它多年而没有问题。但是目前我正在开发一个主方法应用程序,出于性能原因需要 运行 个并发线程,并且这些线程每个都需要访问同一个数据库。如果我完全删除数据库代码并仅将数组用于测试目的(例如多线程工作),我的代码就可以工作了,但是一旦我重新添加数据库连接,第一个线程就会获取锁而其他线程不会t 运行 根本没有。玩过c3p0和dbcp2;目前正在使用 dbcp2。谢谢!那里有大量文档,但似乎特定于我的用例的代码示例并不多。这是一个示例应用程序:
import java.sql.*;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.dbcp2.Utils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
public class SandboxApp {
private static BasicDataSource dataSource;
public static BasicDataSource getDataSource() {
if (dataSource == null) {
BasicDataSource ds = new BasicDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/my-db");
ds.setUsername("root");
ds.setPassword("");
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setInitialSize(3);
ds.setMaxTotal(25);
ds.setMinIdle(0);
ds.setMaxIdle(8);
ds.setMaxOpenPreparedStatements(100);
dataSource = ds;
}
return dataSource;
}
public static void main(String [] args) throws Exception{
for(int i=0; i<11; i++){//spawn 11 threads & get each thread to process 600k sql rows at the same time
new Thread("" + (i*600000)){
public void run(){
System.out.println("Thread: " + getName() + " running");//prints correctly for all threads
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = SandboxApp.getDataSource().getConnection();
pstmt = con.prepareStatement("select something from some_table limit "+getName()+",600000");
rs=pstmt.executeQuery();
while(rs.next()){
System.out.println("Doing stuff for thread "+getName());//this only prints for getName() == 0
//give the other threads a turn...
try {
Thread.sleep(10);
}
catch(InterruptedException ex) {
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {pstmt.close();} catch (SQLException e) {}
try { con.close(); } catch(Exception e) {}
try { rs.close(); } catch(Exception e) {}
}
}
}.start();
}
}
}
@user207421 是对的,应该同步 getDataSource() 方法,当然我已经试过了;然而,这仍然没有解决我的线程“0”不让其他线程轮流的问题。
我从我的代码、所有其他库等中剥离了所有内容。直到我让它工作,然后重新开始构建它以找到突破点。似乎主要的决定因素是 ResultSet 的大小。我尝试在不同的地方添加额外的 thread.sleep 时间,但唯一有效的方法是分解查询以请求更小的结果集。
600k 个结果集,只有 1 个线程 运行,1k 个结果集和 4 个线程 运行。对于仅包含 100 行的 ResultSet,所有 11 个线程都将 运行。请注意,我在一个 16 CPU 系统上对此进行了测试,其中 8GB 内存分配给了 JVM (aws m5.4xlarge),因此硬件资源不应该是一个影响因素。所以我想我只需要将我的代码分成更小的块。
当我最初研究这个问题时,我很惊讶缺少针对这个特定问题的特定代码示例(无论结果集大小和线程数如何),所以我只是在这里发布最终有效的方法为了完整的代码示例,我:
import java.sql.*;
import org.apache.commons.dbcp2.BasicDataSource;
public class SandboxApp {
private static BasicDataSource dataSource;
public static synchronized BasicDataSource getDataSource() {
if (dataSource == null) {
BasicDataSource ds = new BasicDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/my-db");
ds.setUsername("root");
ds.setPassword("");
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setInitialSize(3);
ds.setMaxTotal(25);
ds.setMinIdle(0);
ds.setMaxIdle(8);
ds.setMaxOpenPreparedStatements(100);
dataSource = ds;
}
return dataSource;
}
public static void main(String [] args) throws Exception{
for(int i=0; i<11; i++){//spawn 11 threads & get each thread to process 100 sql rows at the same time
new Thread("" + (i*100)){
public void run(){
System.out.println("Thread: " + getName() + " running");
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = SandboxApp.getDataSource().getConnection();
pstmt = con.prepareStatement("select something from some_table limit "+getName()+",100");
rs=pstmt.executeQuery();
while(rs.next()){
System.out.println("Doing stuff for thread "+getName());//With smaller ResultSet, this works fine for all 11 threads
//give the other threads a turn...
try {
Thread.sleep(10);
}
catch(InterruptedException ex) {
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {pstmt.close();} catch (SQLException e) {}
try { con.close(); } catch(Exception e) {}
try { rs.close(); } catch(Exception e) {}
}
}
}.start();
}
}
}
我非常熟悉在 tomcat 上使用连接池并且已经使用它多年而没有问题。但是目前我正在开发一个主方法应用程序,出于性能原因需要 运行 个并发线程,并且这些线程每个都需要访问同一个数据库。如果我完全删除数据库代码并仅将数组用于测试目的(例如多线程工作),我的代码就可以工作了,但是一旦我重新添加数据库连接,第一个线程就会获取锁而其他线程不会t 运行 根本没有。玩过c3p0和dbcp2;目前正在使用 dbcp2。谢谢!那里有大量文档,但似乎特定于我的用例的代码示例并不多。这是一个示例应用程序:
import java.sql.*;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.dbcp2.Utils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
public class SandboxApp {
private static BasicDataSource dataSource;
public static BasicDataSource getDataSource() {
if (dataSource == null) {
BasicDataSource ds = new BasicDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/my-db");
ds.setUsername("root");
ds.setPassword("");
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setInitialSize(3);
ds.setMaxTotal(25);
ds.setMinIdle(0);
ds.setMaxIdle(8);
ds.setMaxOpenPreparedStatements(100);
dataSource = ds;
}
return dataSource;
}
public static void main(String [] args) throws Exception{
for(int i=0; i<11; i++){//spawn 11 threads & get each thread to process 600k sql rows at the same time
new Thread("" + (i*600000)){
public void run(){
System.out.println("Thread: " + getName() + " running");//prints correctly for all threads
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = SandboxApp.getDataSource().getConnection();
pstmt = con.prepareStatement("select something from some_table limit "+getName()+",600000");
rs=pstmt.executeQuery();
while(rs.next()){
System.out.println("Doing stuff for thread "+getName());//this only prints for getName() == 0
//give the other threads a turn...
try {
Thread.sleep(10);
}
catch(InterruptedException ex) {
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {pstmt.close();} catch (SQLException e) {}
try { con.close(); } catch(Exception e) {}
try { rs.close(); } catch(Exception e) {}
}
}
}.start();
}
}
}
@user207421 是对的,应该同步 getDataSource() 方法,当然我已经试过了;然而,这仍然没有解决我的线程“0”不让其他线程轮流的问题。
我从我的代码、所有其他库等中剥离了所有内容。直到我让它工作,然后重新开始构建它以找到突破点。似乎主要的决定因素是 ResultSet 的大小。我尝试在不同的地方添加额外的 thread.sleep 时间,但唯一有效的方法是分解查询以请求更小的结果集。
600k 个结果集,只有 1 个线程 运行,1k 个结果集和 4 个线程 运行。对于仅包含 100 行的 ResultSet,所有 11 个线程都将 运行。请注意,我在一个 16 CPU 系统上对此进行了测试,其中 8GB 内存分配给了 JVM (aws m5.4xlarge),因此硬件资源不应该是一个影响因素。所以我想我只需要将我的代码分成更小的块。
当我最初研究这个问题时,我很惊讶缺少针对这个特定问题的特定代码示例(无论结果集大小和线程数如何),所以我只是在这里发布最终有效的方法为了完整的代码示例,我:
import java.sql.*;
import org.apache.commons.dbcp2.BasicDataSource;
public class SandboxApp {
private static BasicDataSource dataSource;
public static synchronized BasicDataSource getDataSource() {
if (dataSource == null) {
BasicDataSource ds = new BasicDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/my-db");
ds.setUsername("root");
ds.setPassword("");
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setInitialSize(3);
ds.setMaxTotal(25);
ds.setMinIdle(0);
ds.setMaxIdle(8);
ds.setMaxOpenPreparedStatements(100);
dataSource = ds;
}
return dataSource;
}
public static void main(String [] args) throws Exception{
for(int i=0; i<11; i++){//spawn 11 threads & get each thread to process 100 sql rows at the same time
new Thread("" + (i*100)){
public void run(){
System.out.println("Thread: " + getName() + " running");
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = SandboxApp.getDataSource().getConnection();
pstmt = con.prepareStatement("select something from some_table limit "+getName()+",100");
rs=pstmt.executeQuery();
while(rs.next()){
System.out.println("Doing stuff for thread "+getName());//With smaller ResultSet, this works fine for all 11 threads
//give the other threads a turn...
try {
Thread.sleep(10);
}
catch(InterruptedException ex) {
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {pstmt.close();} catch (SQLException e) {}
try { con.close(); } catch(Exception e) {}
try { rs.close(); } catch(Exception e) {}
}
}
}.start();
}
}
}