单独线程锁父中的 Java JDBC 查询

Posted

技术标签:

【中文标题】单独线程锁父中的 Java JDBC 查询【英文标题】:Java JDBC query in separate thread lock parent 【发布时间】:2012-08-21 13:52:43 【问题描述】:

我很难理解这一点。 这是正在发生的事情。 我正在生成一个新线程,该线程拥有与 Oracle 数据库的 JDBC 连接。 当我要求它连接到数据库时,父线程在调用 start() 方法时继续运行,但是当我要求子线程执行查询(在单独的方法上)时,父线程卡住等待子线程的方法来完成它的工作。 任何猜测如何解决这个问题? 提前致谢!

public class Main extends Thread

    public Main()
    
    

    public void myCounter() 
        int i = 0;
        DBConnection myConnection = null;
        for(;;)
        
            i++;

            System.out.println("time: " + i);
            if( i  == 5)
            
                myConnection = new DBConnection("localhost", 1521, "hr", "hr", "XE");
                myConnection.start();


            
            if(i == 10)
                try 

                    myConnection.runQuery("Select * from hr.numbers order by dbms_random.value");
                 catch (SQLException e) 
                    e.printStackTrace();
                
            try 
                Thread.sleep(1000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

    public void run()
    
        myCounter();
    

    public static void main(String[] args) 

        Main boot = new Main();
        boot.start();

    



public class DBConnection extends Thread

    Connection myConnection;
    int port;
    String user;
    String password;
    String serviceName;
    String host;


    public void run()
    
        setUpConnection(host, port, user, password, serviceName);
    
    /**
     * Sets up variables to create a connection to Oracle.
     *  
     * @param host      host
     * @param port      port
     * @param user      user
     * @param password  password
     */
    public DBConnection(String host, int port, String user, String password, String serviceName)
    
        this.host = host;
        this.port = port;
        this.user = user;
        this.password = password;
        this.serviceName = serviceName;
    


    private void setUpConnection(String host, int port, String user,
            String password, String dataBase) 
        System.out.println("-------- Oracle "
                + "JDBC Connection Testing ------------");

        try 

            Class.forName("oracle.jdbc.OracleDriver");

         catch (ClassNotFoundException e) 

            System.out.println("Couldn't find Oracle JDBC Driver... :-(");
            e.printStackTrace();
            return;

        

        System.out.println("Oracle JDBC Driver Registered!");
        myConnection = null;
        try 
            myConnection = DriverManager.getConnection(
                    "jdbc:oracle:thin:@//" 
                            + host 
                            + ":" 
                            + port 
                            + "/" 
                            + dataBase,
                            user, password
                    );

         catch (SQLException e) 

            System.out.println("Connection Failed!");
            e.printStackTrace();
            return;

        

        if (myConnection != null) 
            System.out.println("Connected to Oracle! :-)");
         else 
            System.out.println("Failed to make connection!");
        
    


    /**
     * Queries the database and returns a ResultSet
     * @param  query            SQL
     * @throws SQLException 
     */
    public  ResultSet runQuery(String query) throws SQLException 
    
        System.out.println("                                                    [DBConnection] Started Running @ " + (new SimpleDateFormat("HH:mm:ss:S")).format(new Date()));
        ResultSet rs = null;

        Statement stt = myConnection.createStatement();
        rs = stt.executeQuery(query);
        System.out.println("                                                    [DBConnection] Finished Running @: " + (new SimpleDateFormat("HH:mm:ss:S")).format(new Date()));
        return  rs;

    

这是我得到的输出:

time: 1
time: 2
time: 3
time: 4
time: 5
-------- Oracle JDBC Connection Testing ------------
Oracle JDBC Driver Registered!
time: 6
Connected to Oracle! :-)
time: 7
time: 8
time: 9
time: 10
                                                    [DBConnection] Started Running @ 14:46:00:660
                                                    [DBConnection] Finished Running @: 14:46:12:750
time: 11
time: 12
time: 13
time: 14

... ... .. .

【问题讨论】:

顺便说一句,我故意创建了包含 1.000.000+ 条记录的 hr.numbers 表,因此需要很长时间才能完成。 您正在主线程上调用 runQuery 方法。 sintaxe 确实根本没有帮助,但是您的 myConnection 是一个新线程这一事实并不会使您调用 runQuery 在新线程中执行。您必须在运行方法中检查一个标志以启动查询(在 myConnection 上)并将其简单地标记在父级上。类似 if (flag) runQuery();elsespleep(1000) 【参考方案1】:

我认为您误解了线程的工作原理。问题是您在父线程上调用它:

myConnection.runQuery("Select * from hr.numbers order by dbms_random.value");

这是对myConnection 对象的runQuery 方法的顺序调用恰好是一个线程。这并不意味着它将指示孩子执行该方法。相反,父线程会自己执行它,而子线程会在其 run 方法返回后立即结束。

如果您想拥有一个单独的线程来持续接收命令以执行查询,您将必须实现一个生产者-消费者模式,在这种模式下,父进程不断排队等待子进程执行的命令。为此我建议你看看ExecutorService。

【讨论】:

是的,这很有意义。通过执行以下操作你会做什么:创建另一个线程来处理对 DBConnection 对象的请求?像 Main 创建一个 DBHandler 对象。另一方面,DBHandler 创建一个 DBConnection 对象,该对象实际上是查询数据库的类。所以 Main 会向 DBHandler 询问东西,DBHandler 一直在等待 DBConnection 返回结果。你怎么看? 当然要看看ExecutorService。如果有什么东西可以简化我的工作,我会非常乐意使用它。但我仍然想知道是否有某种解决方法:-) @user885878:可以。您只需要弄清楚如何将查询传递给子线程以执行。一个简单的方法是使用Executor.newSingleThreadExecutor()。这将有效地创建一个子线程,不断轮询任务队列(所有在幕后)。在这些任务中,您可以放置​​查询,当孩子到达时会自动执行。 太棒了!非常感谢您的帮助!我现在就去看看!祝你有美好的一天! @user885878:你也是。祝你好运!【参考方案2】:

当您调用myConnection.runQuery() 时,您是在父线程的run() 方法中,因此即使您调用其中一个方法,您也不在connection 线程中。

你应该在myConnectionrun()方法中调用runQuery来实现你想要的。

【讨论】:

【参考方案3】:

你的runQuery 方法是阻塞的,因为你在主线程上调用它(所以它会等到查询完成)。如果您希望在另一个线程上调用它,请在另一个线程上调用它run 方法(只需启动您最初为查询方法调用的另一个线程)

【讨论】:

以上是关于单独线程锁父中的 Java JDBC 查询的主要内容,如果未能解决你的问题,请参考以下文章

多线程操作(锁)

Java线程中的同步

如何使用 Java 在不同的线程上或作为不同的进程运行不同的 sql 查询

java面试啥是多线程

Java中的锁原理锁优化CASAQS详解

Java内存模型和线程安全