Pergunta

I'm investigating concurrency when doing multiple queries in different threads. I am using Apache DBCP and DBUtils not because I want to complicate my life but because they should guarantee that the queries are handled correctly and so the concurrency.

However even with the above cool tools I get a:

Error : org.h2.jdbc.JdbcSQLException: Das Objekt wurde bereits geschlossen
The object is already closed [90007-148]
Error : java.lang.NullPointerException

Which is the same kind of error I got also when using Database and Connection objects by hand. It happens one time every 5-6 runs of the program, but this is just a toy program, in a real world application this kind of errors would pop up continuously.

Below my example code

DatatTransaction.java

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;

public class DataTransaction
{
    private final static String username = "";
    private final static String password = "";
    private final static String url = "db" + File.separator + "persondb;create=true";
    public static Connection connection = null;
    public static BasicDataSource dataSource;

    public DataTransaction(boolean setCon)
    {
        try
        {
            setConnectionTest();
        }
        catch (Exception e)
        {
            System.out.println("Error in Connection:" + e.toString());
        }
    }

    public final void setConnectionTest() throws SQLException
    {
        try
        {
            if (dataSource == null)
            {
                dataSource = new BasicDataSource();
                String driver = "org.h2.Driver";
                try
                {
                    dataSource.setDriverClassName(driver);
                    dataSource.setUrl("jdbc:h2:"+url);
                    dataSource.setUsername(username);
                    dataSource.setPassword(password);
                    dataSource.setMaxActive(100);
                    dataSource.setMaxWait(10000);
                    dataSource.setMaxIdle(10);
                    if (connection == null || connection.isClosed())
                    {
                        connection = dataSource.getConnection();
                    }
                }
                catch (SQLException e)
                {
                    System.out.println("Could not connect to the database msg :" + e.getMessage());
                }
            }
            else
            {
                connection = dataSource.getConnection();
            }
        }
        catch (Exception e)
        {
            System.out.println("open connection exception" + e);
        }
    }
}

and DBTest2.java

package dbtest;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class DBTest2
{

    public static void main(String[] args)
    {
        try
        {
            new Thread(db1).start();
            new Thread(db2).start();
        }
        catch (Exception e)
        {
            System.out.println("MM : Error : " + e);
        }
    }
    private static Runnable db1 = new Runnable()
    {
        public void run()
        {
            try
            {
                for (int i = 0; i < 50; i++)
                {
                    DBTest2 dBTest = new DBTest2();
                    List<Object[]> list1 = dBTest.DB1();
                    for (Object[] object : list1)
                    {
                        System.out.println("DB1 : FirstName : " + object[0] + " Lastname: " + object[1]);
                    }
                }
            }
            catch (Exception e)
            {
                System.out.println("Error : " + e);
            }
        }
    };

    private static Runnable db2 = new Runnable()
    {
        public void run()
        {
            try
            {
                for (int i = 0; i < 50; i++)
                {
                    DBTest2 dBTest = new DBTest2();
                    List<Object[]> list = dBTest.DB2();
                    for (Object[] object : list)
                    {
                        System.out.println("DB2 : FirstName : " + object[0] + " Lastname: " + object[1]);
                    }
                }
            }
            catch (Exception e)
            {
                System.out.println("Error : " + e);
            }
        }
    };

    public List<Object[]> DB1()
    {
        try
        {
            DataTransaction dt = new DataTransaction(true);
            Connection conn = dt.connection;
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("select NAME,SURNAME from PERSON");
            ResultSetMetaData rsmd = rs.getMetaData();
            int dataCnt = rsmd.getColumnCount();
            List<Object[]> list = new ArrayList<Object[]>();
            while (rs.next())
            {
                Object[] data = new Object[dataCnt];
                for (int i = 0; i < dataCnt; i++)
                {
                    data[i] = rs.getString(i + 1);
                }
                list.add(data);
            }
            conn.close();
            return list;
        }
        catch (Exception e)
        {
            System.out.println("Error : " + e);
            return null;
        }
    }

    public List<Object[]> DB2()
    {
        try
        {
            DataTransaction dt = new DataTransaction(true);
            Connection conn = dt.connection;
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("select NAME,SURNAME from PERSON");
            ResultSetMetaData rsmd = rs.getMetaData();
            int dataCnt = rsmd.getColumnCount();
            List<Object[]> list = new ArrayList<Object[]>();
            while (rs.next())
            {
                Object[] data = new Object[dataCnt];
                for (int i = 0; i < dataCnt; i++)
                {
                    data[i] = rs.getString(i + 1);
                }
                list.add(data);
            }
            conn.close();
            return list;
        }
        catch (Exception e)
        {
            System.out.println("Error : " + e);
            return null;
        }
    }
}
Foi útil?

Solução

You should have a read of derby pitfalls in it there are some common pitfalls, the one you are interested in is:

"Executing a Statement automatically closes any existing open ResultSet generated by an earlier execution of that Statement. If threads share Statements, one thread could close another's ResultSet. In many cases, it is easier to assign each thread to a distinct Connection. "

Ok so the problem with your code is DatatTransaction.java, change the code by removing the static variable connection and add this method:

    public final Connection getConnection()
{
    Connection conn = null;
    try
    {
        conn = dataSource.getConnection();
    }
    catch (SQLException e)
    {
        System.out.println("Could not connect to the database msg :" + e.getMessage());
    }
    return conn;
}

Now it will no longer give any problem (by the way, if you comment the System.out.println() in your example you will see more quickly and more often the concurrency errors which are otherwise mitigated by the time needed to print to the console).

As for the "exceptionorg.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object " that's because you are not closing the resources correctly by commenting the close() methods, so you quickly run out of connections in the pool.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top