Пул соединений с использованием Apache общих DBCP и DBUtils и параллелизма
Я исследую параллелизм при выполнении нескольких запросов в разных потоках. Я использую Apache DBCP и DBUtils не потому, что хочу усложнить свою жизнь, а потому, что они должны гарантировать, что запросы обрабатываются правильно и, следовательно, параллелизм.
Однако даже с вышеупомянутыми классными инструментами я получаю:
Error : org.h2.jdbc.JdbcSQLException: Das Objekt wurde bereits geschlossen
The object is already closed [90007-148]
Error : java.lang.NullPointerException
Какую же ошибку я получаю и при ручном использовании объектов базы данных и соединения. Это происходит один раз каждые 5-6 запусков программы, но это просто игрушечная программа, в реальном приложении такого рода ошибки будут появляться постоянно.
Ниже мой пример кода
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);
}
}
}
и 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;
}
}
}
1 ответ
Вы должны прочитать о подводных камнях в дерби. Есть несколько распространенных ошибок, которые вас интересуют:
"Выполнение Statement автоматически закрывает любой существующий открытый ResultSet, сгенерированный более ранним выполнением этого Statement. Если потоки совместно используют Statements, один поток может закрыть ResultSet другого. Во многих случаях легче назначить каждый поток отдельному Connection".
Итак, проблема с вашим кодом - DatatTransaction.java, измените код, удалив соединение со статической переменной, и добавьте этот метод:
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;
}
Теперь это больше не создаст никаких проблем (кстати, если вы прокомментируете System.out.println() в своем примере, вы увидите более быстрые и частые ошибки параллелизма, которые в противном случае уменьшаются за счет времени, необходимого для печати на приставка).
Что касается "exceptionorg.apache.commons.dbcp.SQLNestedException: не удается получить соединение, ошибка пула Тайм-аут ожидания незанятого объекта", это потому, что вы неправильно закрываете ресурсы, комментируя методы close(), поэтому вы быстро исчерпываете соединения в бассейне.