Понимание JdbcConnectionPool с базой данных H2
У меня есть серверный процесс H2, запущенный на моей основной серверной машине, разрешающий TCP-соединения.
Допустим, я хочу выполнить 100 SQL-запросов:
SELECT * FROM TEST
И, для моих собственных целей, я хочу сделать один запрос на поток. Давайте сделаем это с одним и только одним Connection
объектом, общим для потоков:
- создайте один объект
Connection
. - создайте 100 потоков.
- в каждом потоке используйте объект shared
Connection
для вызова SQL-запроса.
Вышеуказанная воля работайте, но это будет немного медленно. Конечно, в конце концов, если кто-то использует Connection
, то другие должны ждать его.
Ну тогда давайте сделаем по одному Connection
на поток:
- создайте 100 потоков.
- в каждом потоке создайте новый объект
Connection
и вызовите SQL-запрос.
JdbcConnectionPool
для такого рода вещь.
- создайте
JdbcConnectionPool
с максимальным числом соединений 50. - создайте 100 потоков.
- в каждом потоке используйте
pool.getConnection()
, а затем вызовите SQL-запрос.
Ха. Это медленно. Во всяком случае, это так же медленно, как и первый подход. Может быть, из любопытства я должен установить максимум связей на 100
...
... и это все еще медленно. Странный. Я понимал, что пул со 100 соединениями будет эквивалентен созданию одного соединения для каждого из моих 100 нитей.
В чем может быть проблема? Вот код для последнего теста:
import java.sql.Connection;
import java.sql.ResultSet;
import org.h2.jdbcx.JdbcConnectionPool;
public class App {
public static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
JdbcConnectionPool pool = JdbcConnectionPool.create("url", "user", "password");
pool.setMaxConnections(100);
for (int i = 0; i < 100; ++i) {
Thread t = new Thread(new Client(i, pool));
t.start();
}
}
}
class Client implements Runnable {
int id;
JdbcConnectionPool pool;
public Client(int id, JdbcConnectionPool pool) {
this.id = id;
this.pool = pool;
}
public void run() {
try {
Connection conn = pool.getConnection();
ResultSet set = conn.createStatement().executeQuery("SELECT * FROM TEST");
if (set.next()) {
System.out.println("Finished " + id);
}
set.close();
conn.close();
}catch (Exception e) {
}
}
}
Я использую H2 1.4.182
.
1 ответ:
Исходный код JdbcConnectionPool#getConnection():
public Connection getConnection() throws SQLException { long max = System.currentTimeMillis() + timeout * 1000; do { synchronized (this){ if (activeConnections < maxConnections) { return getConnectionNow(); } try { wait(1000); } catch (InterruptedException e) { // ignore } } } while (System.currentTimeMillis() <= max); throw new SQLException("Login timeout", "08001", 8001); }
Одной из самых дорогостоящих операций в вашем примере является создание соединения. Как вы можете видеть, метод
getConnection()
имеет блокировку синхронизированную (эту) , поэтому только один поток может создать соединение одновременно, а все остальные потоки находятся в ожидании.Я считаю, что встроенный пул соединений h2 довольно прост. Если вы хотите иметь высокопроизводительный пул соединений, вы можете посмотреть на C3P0 или BoneCP.