Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java JDBC query in separate thread lock parent

I'm having some trouble understanding this. Here's what's happening. I'm spawning a new thread that holds a JDBC connection to a Oracle database. When I ask it to connect to the database, the parent thread keeps running while the start() method is invoked but when I ask the child to execute a query (on a separate method), the parent thread gets stuck waiting for the child thread's method to finish doing its work. Any guess as how to fix this? Thanks in advance!

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;

    }

Here's the output I get:

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

... ... .. .

like image 940
Yaroze Avatar asked Aug 21 '12 13:08

Yaroze


2 Answers

I think you have misunderstood a bit how threads work. The problem is that you are calling this on the parent thread:

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

which is a sequential invocation of the runQuery method on the myConnection object that happens to be a thread. This does not mean that it will instruct the child to execute the method. Instead the parent will execute it itself and the child thread finishes as soon as its run method has returned.

If you want to have a separate thread that keeps receiving commands to execute queries you will have to implement a producer-consumer pattern, where the parent keeps queuing commands for the child to execute. To this end I recommend you look at ExecutorService.

like image 181
Tudor Avatar answered Oct 16 '22 22:10

Tudor


When you call myConnection.runQuery(), you are inside the run() method of the parent thread, so you are not in the connection thread even if you call one of its methods.

You should call runQuery inside the run() method of myConnection to achieve what you want.

like image 36
jolivier Avatar answered Oct 17 '22 00:10

jolivier