【问题标题】:JDBC and MultithreadingJDBC 和多线程
【发布时间】:2016-08-21 18:12:09
【问题描述】:

我正在尝试使用多线程方法运行几个查询,但是我认为我做错了什么,因为我的程序需要大约五分钟来运行一个简单的 select 语句,例如

SELECT * FROM TABLE WHERE ID = 123'

我的实现如下,我正在使用一个连接对象。

在我的运行方法中

public void run() {
    runQuery(conn, query);
}

runQuery 方法

public void runQuery(Connection conn, String queryString){
    Statement statement;
    try {
          statement = conn.createStatement();
          ResultSet rs = statement.executeQuery(queryString);
          while (rs.next()) {}
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

最后在 main 方法中,我使用下面的 sn-p 启动线程。

MyThread bmthread = new MyThread(conn, query);
ArrayList<Thread> allThreads = new ArrayList<>();
double start = System.currentTimeMillis();
    int numberOfThreads = 1;
    for(int i=0; i<=numberOfThreads; i++){
        Thread th = new Thread(bmthread);
        th.setName("Thread "+i);
        System.out.println("Starting Worker "+th.getName());
        th.start();
        allThreads.add(th);
    }

    for(Thread t : allThreads){
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
double end = System.currentTimeMillis();
double total = end - start;
System.out.println("Time taken to run threads "+ total);

更新:我现在为每个线程使用单独的连接。

ArrayList<Connection> sqlConn = new ArrayList<>();
    for(int i =0; i<10; i++){
        sqlConn.add(_ut.initiateConnection(windowsAuthURL, driver));
    } 
loop:
  MyThread bmthread = new MyThread(sqlConn.get(i), query);

【问题讨论】:

  • 您能否添加更多信息:您使用的是什么数据库?你是如何构建连接的?没有所有线程的东西,只有一个查询需要多长时间?
  • 我使用的是 SQL Server 2008。没有线程的东西,代码在几毫秒内执行。实际上不到一秒钟。

标签: java sql database multithreading jdbc


【解决方案1】:

正如 rohivats 和 Asaph 所说,一个连接必须由一个且只有一个线程使用,也就是说,考虑使用数据库连接池。考虑到 c3p0、DBCP 和类似的东西几乎都被抛弃了,我会使用HikariCP,它非常快速且可靠。

如果你想要一些非常简单的东西,你可以使用线程安全集合(例如 LinkedList)实现一个非常简单的连接池,例如:

 public class CutrePool{
      String connString;    
      String user;
      String pwd;

      static final int INITIAL_CAPACITY = 50;
      LinkedList<Connection> pool = new LinkedList<Connection>();
      public String getConnString() {
          return connString;
      }
      public String getPwd() {
          return pwd;
      }

      public String getUser() {
          return user;
      }

      public CutrePool(String connString, String user, String pwd) throws SQLException {
          this.connString = connString;
        
          for (int i = 0; i < INITIAL_CAPACITY; i++) {
               pool.add(DriverManager.getConnection(connString, user, pwd));
          }
          this.user = user;
          this.pwd = pwd;
      }

      public synchronized Connection getConnection() throws SQLException {
          if (pool.isEmpty()) {
              pool.add(DriverManager.getConnection(connString, user, pwd));
          }
          return pool.pop();
      }
    
      public synchronized void returnConnection(Connection connection) {
          pool.push(connection);
      }  
  }

如您所见,getConnection 和 returnConnection 方法是同步的,以保证线程安全。获取连接(conn = pool.getConnection();),使用后别忘了返回/释放连接(pool.returnConnection(conn);

【讨论】:

  • 我会看看 HirakiCP 并告诉你进展如何。
  • 您也可以使用单例模式实现自己的池连接,但我不喜欢重新发明轮子:
  • 我编辑了我的答案,以防您需要一个非常简单的连接池实现。
  • 很好的实现。我几乎有相同的,但它使用的是 ArrayList。我接受了你的回答。
  • 谢谢!小心使用 ArrayList 因为它不是线程安全的,所以你需要将集合与 synchronized(list) 块同步
【解决方案2】:

不要在所有线程中使用相同的连接对象。给每个线程一个专用的数据库连接。

【讨论】:

  • 我为每个线程使用了不同的连接,请参阅我的问题中的更新。现在需要 33 秒。但是,如果我在 SQL Server Management Studio 中运行,相同的查询需要 1 秒。
  • 我注意到您问题中的查询有一个尾随单引号。那是错字吗?该查询中的数字是否用单引号括起来?
  • @Asaph,是的,这是一个错字!
【解决方案3】:

一个Connection 一次只能执行一个查询。您需要多个可用连接来并行执行数据库操作。尝试将DataSource 与连接池一起使用,并让每个线程从池中请求连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 2023-01-06
    • 1970-01-01
    • 2018-02-23
    • 2012-06-13
    • 1970-01-01
    • 2016-04-17
    相关资源
    最近更新 更多