2016-03-03 74 views
0

我有一个线程,它在其中创建与Oracle DB的连接,读取内容并写入csv文件。在每个线程中,来自DB的内容都被写入到单独的csv文件中。由于建立了数量为n的连接,它会引发一个异常,说“ORA-00018:超过最大会话数”。请提供一个解决方案来阻止它,但代码应该在同一时间运行。下面是使用的代码。在JAVA中使用多线程限制Oracle连接数的解决方案

host s1 = new host(SYSNAME,SYSID); 
    s1.start(); 

    class host extends Thread{ 
    String SYSNAME,SYSID; 
    public host(String SYSNAME, String SYSID){ 
     this.SYSNAME = SYSNAME; 
     this.SYSID = SYSID; 
    } 
    public void run(){ 
     Connection conn; 
    try{ 
     Class.forName("oracle.jdbc.driver.OracleDriver"); 
     conn = DriverManager.getConnection(url, username, pwd); 
     String csv_file = "AverageValuesHost-" + SYSNAME + "-" + SYSID + "_Result.csv"; 
     String host_query = null; 
     host_query = "My query"; 
     ResultSet res_host = conn.createStatement().executeQuery(host_query); 

     CSVWriter wr = new CSVWriter(new FileWriter(csv_file), ','); 
     wr.writeAll(res_host, true); 
     wr.flush(); 
     wr.close(); 
     conn.close(); 
    } 
+2

数据库只允许连接到它。使用连接池(c3p0或dbcp)或增加可建立的连接数(修改oracle的最大连接数)。 – honerlawd

+1

@Kiran:您需要重构代码,以便获取与数据库的连接应该来自连接池(同步)。您的线程需要访问该连接池并获得与数据库的连接,如果没有连接,则线程应该进入睡眠状态。 – Lathy

+0

@Lathy:希望你不明白我的问题。因为所有线程都有自己的功能,所以没有任何同步点。线程不依赖于 –

回答

0

你可以尝试这样的事情。 1.创建自定义线程,并在该线程中初始化db连接 2.创建一个ThreadPoolExecutor到fixedThreadPool(),以传递no连接作为参数,此TPE也应该采用自定义线程工厂 3.创建一个Runnable类,并访问 3.对于每个查询使可运行并提交给bq。 4.请勿在Runnable内使用任何等待/通知/或任何其他同步。一旦一个Runnable在你的线程内开始执行,它将完成Runnable的执行。它锁定底层线程。 [来自TPE代码]

这是一个非正统的方法,我从来没有见过一个Runnable正在从线程(自定义)类中取出一个对象来执行。但我没有发现任何问题,如果我错了,有人可以纠正我。

我做了一个原型,请看看,让我知道它是否符合您的目的。那么,这可以在许多方面得到改进,例如异常处理,拒绝处理等。但首先应该实现快乐的道路或目的。

感谢

package com.stackoverflow.dbconpool; 

import java.sql.Connection; 

public class DBConnectionThread extends Thread { 
    Connection con; 

    public Connection getCon() { 
     return con; 
    } 

    public DBConnectionThread(Runnable r) { 
     super(r); 
     con = null;// initialize with parameters to make a connection with db. 
     // if you want any custom parameter to be passed, you can create a 
     // separate Runnable 
     // and take values from that runnable to initialize DBConnectionThread. 
    } 

} 


package com.stackoverflow.dbconpool; 

import java.util.concurrent.ThreadFactory; 

public class DBConnectionThreadFactory implements ThreadFactory { 

    @Override 
    public Thread newThread(Runnable r) { 
     DBConnectionThread t = new DBConnectionThread(r); 
     return t; 
    } 
} 



package com.stackoverflow.dbconpool; 

import java.sql.Connection; 
import java.util.Random; 

public class ExecuteQueryRunnable implements Runnable { 

    Random rand; 
    int index; 

    public ExecuteQueryRunnable(Random rand, int i) { 
     this.rand = rand; 
     this.index = i; 
    } 

    @Override 
    public void run() { 
     System.out.println("Executing DB Query " + index + " inside $$" 
       + Thread.currentThread().getId()); 
     long threadId = Thread.currentThread().getId(); 
     DBConnectionThread thread = (DBConnectionThread) Thread.currentThread(); 
     Connection con = thread.getCon(); 
     // // execute query code, stament creation etc etc. 
     System.out.println("completed executing DB query -" + index 
       + "- inside $$" + Thread.currentThread().getId()); 
     long threadIdFinish = Thread.currentThread().getId(); 
     if (threadIdFinish != threadId) 
      System.out.println("@@@@@@@@@@@@@@"); 
    } 
} 


package com.stackoverflow.dbconpool; 

import java.util.Random; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class TestMultiDB { 
    public static void main(String[] args) { 
     Random rand = new Random(); 
     ExecutorService es = Executors.newFixedThreadPool(3, 
       new DBConnectionThreadFactory()); 
     // BlockingQueue<ExecuteQueryRunnable> queryQueue = new 
     // ArrayBlockingQueue<ExecuteQueryRunnable>(
     // 10); 
     for (int i = 0; i < 10; i++) { 
      Runnable r = new ExecuteQueryRunnable(rand, i); 
      es.execute(r); 
     } 
     es.shutdown(); 

     while (!es.isTerminated()) { 
     } 
     System.out.println("main terminates "); 
    } 
} 
+0

梦幻般的尝试。但是这减慢了速度。因为在我的情况下,要创建的2000个文件每个都有1000个条目的数据。 –

2

您需要使用DataSource与连接池来创建连接(例如C3P0或HikariCP)。这允许您指定最大连接数,并且当连接不可用时,线程将被强制等待(直到超时),直到连接可用。

另请注意,创建更多线程并不总是完成更多工作的最佳方式。您也可以考虑使用具有固定数量的线程的ExecutorService,并将作业提交给此执行程序服务。这种方式永远不会超过n作业一次运行,因此您可以限制连接的数量。

只要确保始终关闭连接(当发生异常时,您的当前代码无法正确执行)。看看try-with-resources