Как создать пул соединений в JDBC?

111

Может ли кто-нибудь предоставить примеры или ссылки о том, как установить пул соединений JDBC?

При поиске в Google я вижу много разных способов сделать это, и это довольно сбивает с толку.

В конечном итоге мне нужен код для возврата java.sql.Connectionобъекта, но у меня проблемы с началом работы ... приветствуются любые предложения.

Обновление: нет javax.sqlили java.sqlесть реализации объединенного подключения? Почему бы не использовать их?

LLM
источник
8
Нет, стандартный JDBC не поддерживает пул соединений. Для этого вам понадобится отдельная библиотека. Большинство серверов приложений и контейнеров сервлетов включают пулы соединений. Кроме того, реализации JPA обычно также предоставляют реализации.
Уилл Хартунг,
3
Обновление для современных пользователей Java. JDBC 3.0+ (который, как мне кажется, используется в Java 6?) Имеет реализацию для соединений с объединенными базами данных. Java 7 использует JDBC 4, а Java 8 JDBC 4.1.
BRasmussen
1
Относительно JDBC 3.0 API для пула соединений: progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Арто Бендикен,

Ответы:

102

Если вам нужен пул соединений автономного, мое предпочтение отдается C3P0 над ДБХПОМ (что я уже упоминал в этом предыдущем ответе ), я просто имел слишком много проблем с ГСБДОМ при большой нагрузке. Использовать C3P0 очень просто. Из документации :

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");

// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);

// The DataSource cpds is now a fully configured and usable pooled DataSource 

Но если вы работаете на сервере приложений, я бы рекомендовал использовать встроенный пул соединений, который он предоставляет. В этом случае вам необходимо настроить его (см. Документацию вашего сервера приложений) и получить DataSource через JNDI:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Паскаль Тивент
источник
1
То же самое. Я уже много лет наблюдал за блокировкой DBCP под нагрузкой. Версия за версией.
Василий
да, но и C3P0, у меня лучший опыт работы с BoneCP
Николас Моммартс
1
Похоже, что BoneCP устарел в пользу HikariCP . HikariCP также упоминается в ответе ниже .
kaartic
19

Обычно, если вам нужен пул соединений, вы пишете приложение, которое работает в некоторой управляемой среде, то есть вы работаете на сервере приложений. В этом случае не забудьте проверить, какие средства пула соединений предоставляет ваш сервер приложений, прежде чем пробовать другие варианты.

Готовое решение будет лучше всего интегрировано с остальными возможностями серверов приложений. Однако, если вы не работаете на сервере приложений, я бы порекомендовал компонент Apache Commons DBCP . Он широко используется и обеспечивает все основные функции пула, которые требуются большинству приложений.

Тендаи Мавуше
источник
18

HikariCP

Это современно, быстро, просто. Я использую его для каждого нового проекта. Я предпочитаю его C3P0, не слишком хорошо знаю другие пулы.

Tobijdc
источник
18

Не изобретайте велосипед.

Попробуйте один из легко доступных сторонних компонентов:

  • Apache DBCP - используется Tomcat внутри компании, и искренне ваш.
  • c3p0

Apache DBCP поставляется с другим примером того, как настроить пул javax.sql.DataSource . Вот один пример, который поможет вам начать работу.

Александр Погребняк
источник
1
Он называется C3P0. Между прочим, это более производительно, чем DBCP в многопоточных средах, поскольку DBCP блокирует доступ к одному потоку.
BalusC
@BalusC. Спасибо за исправление, я disclecsiaвзял меня лучше. Вы видите, что ссылка верна. :)
Александр Погребняк
1
@Mudassir. Я бы рекомендовал поискать замену DBCP, добавленную в Tomcat из Spring -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… . Вам не нужен весь сервер Tomcat, чтобы использовать его, только одна банка tomcat-jdbc. Вы можете получить его в Maven Central -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Александр Погребняк
@AlexanderPogrebnyak: Спасибо, Александр, это мило с твоей стороны. Я планирую использовать CP в веб-сервисе Axis. Буду думать над вашим предложением. - Mudassir 7 минут назад
Mudassir
17

Я бы рекомендовал использовать библиотеку commons-dbcp . Существует множество примеров того, как его использовать, вот ссылка на простой ход . Использование очень простое:

 BasicDataSource ds = new BasicDataSource();
 ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
 ds.setUsername("scott");
 ds.setPassword("tiger");
 ds.setUrl(connectURI);
 ...
 Connection conn = ds.getConnection();

Вам нужно создать источник данных только один раз, поэтому обязательно прочтите документацию, если вы не знаете, как это сделать. Если вы не знаете, как правильно писать операторы JDBC, чтобы не допустить утечки ресурсов, вы также можете прочитать эту страницу в Википедии .

Эрик Хаузер
источник
8
Действительно ли это создает пул соединений?
llm
@llm Конечно! Определение javax.sql.DataSourceинтерфейса содержит реализацию «пула соединений» (кроме того, я думаю, вы уже знаете, что такое интерфейс JDBC)
Эдди,
7

На сервере приложений, который мы используем там, где я работаю (Oracle Application Server 10g, насколько я помню), пулы обрабатываются сервером приложений. Мы получаем с javax.sql.DataSourceпомощью поиска JNDI с javax.sql.InitialContext.

это сделано что-то вроде этого

try {     
   context = new InitialContext();
   jdbcURL = (DataSource) context.lookup("jdbc/CachedDS");
   System.out.println("Obtained Cached Data Source ");
}
catch(NamingException e)   
{  
    System.err.println("Error looking up Data Source from Factory: "+e.getMessage());
}

(Мы не писали этот код, он скопирован из этой документации .)

Powerlord
источник
5

Бассейн

  • Механизм объединения - это способ создания объектов заранее. Когда класс загружен.
  • Это улучшает приложение performance[за счет использования одного и того же объекта для выполнения любого действия с объектом-данными] и memory[выделение и освобождение многих объектов создает значительные накладные расходы на управление памятью].
  • Очистка объекта не требуется, поскольку мы используем тот же объект, что снижает нагрузку на сборку мусора.

« ObjectПул [ пул, Stringпостоянный пул, Threadпул, пул соединений]

Постоянный пул строк

  • Пул строковых литералов поддерживает только одну копию каждого отдельного строкового значения. который должен быть неизменным.
  • Когда вызывается метод intern, он проверяет доступность объекта с таким же содержимым в пуле, используя метод equals. «Если String-копия доступна в пуле, то возвращает ссылку. «В противном случае объект String добавляется в пул и возвращает ссылку.

Пример: строка для проверки уникального объекта из пула.

public class StringPoolTest {
    public static void main(String[] args) { // Integer.valueOf(), String.equals()
        String eol = System.getProperty("line.separator"); //java7 System.lineSeparator();

        String s1 = "Yash".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1));
        String s2 = "Yas"+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2));
        String s3 = "Yas".intern()+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3));
        String s4 = "Yas"+"h";
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4));
    }
}

Пул соединений с использованием Type-4 драйвера с использованием 3 - библиотек [ DBCP2, c3p0, Tomcat JDBC]

Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora]. вики

В механизме пула соединений, когда класс загружается, он получает physical JDBC connectionобъекты и предоставляет пользователю завернутый объект физического соединения. PoolableConnectionэто оболочка вокруг фактического соединения.

  • getConnection()выберите одно из свободных обернутых соединений из пула объектов соединения и верните его.
  • close() вместо закрытия он возвращает обернутое соединение обратно в пул.

Пример: использование пула соединений ~ DBCP2 с Java 7 [ try-with-resources]

public class ConnectionPool {
    static final BasicDataSource ds_dbcp2 = new BasicDataSource();
    static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource();
    static final DataSource ds_JDBC = new DataSource();

    static Properties prop = new Properties();
    static {
        try {
            prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties"));

            ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") );
            ds_dbcp2.setUrl( prop.getProperty("URL") );
            ds_dbcp2.setUsername( prop.getProperty("UserName") );
            ds_dbcp2.setPassword( prop.getProperty("Password") );
            ds_dbcp2.setInitialSize( 5 );

            ds_c3p0.setDriverClass( prop.getProperty("DriverClass") );
            ds_c3p0.setJdbcUrl( prop.getProperty("URL") );
            ds_c3p0.setUser( prop.getProperty("UserName") );
            ds_c3p0.setPassword( prop.getProperty("Password") );
            ds_c3p0.setMinPoolSize(5);
            ds_c3p0.setAcquireIncrement(5);
            ds_c3p0.setMaxPoolSize(20);

            PoolProperties pool = new PoolProperties();
            pool.setUrl( prop.getProperty("URL") );
            pool.setDriverClassName( prop.getProperty("DriverClass") );
            pool.setUsername( prop.getProperty("UserName") );
            pool.setPassword( prop.getProperty("Password") );
            pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle)

            pool.setInitialSize(5);
            pool.setMaxActive(3);
            ds_JDBC.setPoolProperties( pool );
        } catch (IOException e) {   e.printStackTrace();
        } catch (PropertyVetoException e) { e.printStackTrace(); }
    }

    public static Connection getDBCP2Connection() throws SQLException {
        return ds_dbcp2.getConnection();
    }

    public static Connection getc3p0Connection() throws SQLException {
        return ds_c3p0.getConnection();
    }

    public static Connection getJDBCConnection() throws SQLException {
        return ds_JDBC.getConnection();
    }
}
public static boolean exists(String UserName, String Password ) throws SQLException {
    boolean exist = false;
    String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
    try ( Connection connection = ConnectionPool.getDBCP2Connection();
          PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) {
        pstmt.setString(1, UserName );
        pstmt.setString(2, Password );

        try (ResultSet resultSet = pstmt.executeQuery()) {
            exist = resultSet.next(); // Note that you should not return a ResultSet here.
        }
    }
    System.out.println("User : "+exist);
    return exist;
}

jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName> jdbc:oracle:thin:@localhost:1521:myDBName jdbc:mysql://localhost:3306/myDBName

connectionpool.properties

URL         : jdbc:mysql://localhost:3306/myDBName
DriverClass : com.mysql.jdbc.Driver
UserName    : root
Password    :

Веб- приложение: чтобы избежать проблем с соединением, когда все соединения закрыты [MySQL "wait_timeout" по умолчанию 8 часов], чтобы повторно открыть соединение с базовой БД.

Вы можете сделать это, чтобы проверить каждое соединение, установив testOnBorrow = true и validationQuery = "SELECT 1" и не используя autoReconnect для сервера MySQL, поскольку он устарел. выпуск

===== ===== context.xml ===== =====
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for a web application -->
<Context>
    <Resource name="jdbc/MyAppDB" auth="Container" 
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        type="javax.sql.DataSource" 

        initialSize="5" minIdle="5" maxActive="15" maxIdle="10"

        testWhileIdle="true"
            timeBetweenEvictionRunsMillis="30000"

        testOnBorrow="true"
            validationQuery="SELECT 1"
            validationInterval="30000"


        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/myDBName" 
        username="yash" password="777"
    />
</Context>

===== ===== web.xml ===== =====
<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/MyAppDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
===== ===== DBOperations ===== =====
servlet «   init() {}
Normal call used by sevlet  « static {}

static DataSource ds;
static {
    try {
        Context ctx=new InitialContext();
        Context envContext = (Context)ctx.lookup("java:comp/env");
        ds  =   (DataSource) envContext.lookup("jdbc/MyAppDB");
    } catch (NamingException e) {   e.printStackTrace();    }
}

См. Также:

Яш
источник
В примере с пулом констант String, я понимаю, когда вы написали: «Если String-copy доступен [.equals ()] в пуле, тогда возвращается ссылка.« В противном случае объект String добавляется в пул и возвращает ссылку ». Но в public class StringPoolTestпросто есть 2 метода void, поэтому они ничего не возвращают. Действительно ли этот код выполняет процесс управления пулом строк? Кажется, он даже не использует никаких аргументов.
jeffery_the_wind 06
@jeffery_the_wind: - это просто чтобы знать концепцию пула, для проверки пула строк я просто использовал методы hashCode, identityHashCode . изменил код ...
Yash
Извините, s1не определено?
jeffery_the_wind 06
Хорошо, просто хотел убедиться, что все это вижу. Я буду работать над этим. Что мне понадобится для чего-то более близкого к твоему ConnectionPoolКлассу. Спасибо.
jeffery_the_wind 06
5

В конце 2017 года Proxool, BoneCP, C3P0, DBCP в настоящее время в основном не функционируют. HikariCP (созданный в 2012 году) кажется многообещающим, он решает все, что я знаю. http://www.baeldung.com/hikaricp

У Proxool есть ряд проблем:
- При большой нагрузке может превышать максимальное количество подключений и не возвращаться ниже максимального
- Может удается не возвращаться к минимальным подключениям даже после истечения срока действия
- Может блокировать весь пул (и все потоки сервера / клиента) если у него возникли проблемы с подключением к базе данных во время потока HouseKeeper (не использует .setQueryTimeout)
- поток HouseKeeper , имея блокировку пула соединений для своего процесса, запрашивает поток Prototyper для воссоздания соединений (развертка), что может привести к состоянию гонки / блокировке. В этих вызовах методов последний параметр всегда должен иметь значение sweep: false во время цикла, только sweep: true под ним.
- HouseKeeper требуется только одна развертка PrototypeController в конце и есть еще [упомянутые выше]
- Поток HouseKeeper проверяет наличие тестирования соединений, прежде чем увидеть, какие соединения могут быть истекшими [некоторый риск тестирования истекшего соединения, которое может быть прервано / прервано из-за других тайм-аутов для БД в брандмауэре и т. Д.]
- Проект имеет незаконченный код (свойства, которые определены но не были приняты меры)
- Максимальный срок службы соединения по умолчанию, если он не определен, составляет 4 часа (чрезмерно)
- Поток HouseKeeper выполняется каждые пять секунд на пул (чрезмерно).

Вы можете изменить код и внести эти улучшения. Но поскольку он был создан в 2003 году и обновлен в 2008 году, ему не хватало почти 10-летних улучшений Java, которые используют такие решения, как hikaricp.

bluejaguar
источник
4

Как ответили другие, вы, вероятно, будете довольны Apache Dbcp или c3p0 . Оба популярны и отлично работают.

Что касается вашего сомнения

Разве javax.sql или java.sql не имеют реализации объединенного соединения? Почему бы не использовать их?

Они не предоставляют реализации, скорее интерфейсы и некоторые классы поддержки, только для программистов, реализующих сторонние библиотеки (пулы или драйверы). Обычно вы даже не смотрите на это. Ваш код должен прозрачно обрабатывать соединения из вашего пула так же, как они были "простыми" соединениями.

leonbloy
источник
4

Vibur DBCP - еще одна библиотека для этой цели. Несколько примеров, показывающих, как настроить его для использования с Hibernate, Spring + Hibernate или программно, можно найти на его веб-сайте: http://www.vibur.org/

Также см. Отказ от ответственности здесь .

Симеон Мальчев
источник
3

В Apache Commons есть библиотека для этой цели: DBCP . Если у вас нет странных требований к вашим пулам, я бы использовал библиотеку, поскольку она обязательно будет сложнее и сложнее, чем вы могли бы надеяться.

бледный
источник
1

Вам следует подумать об использовании UCP. Универсальный пул соединений (UCP) - это пул соединений Java. Это многофункциональный пул соединений, тесно интегрированный с Oracle Real Application Clusters (RAC), ADG, базами данных DG.

Обратитесь к этой странице для получения более подробной информации о UCP.

Нирмала
источник
0

MiniConnectionPoolManager - это реализация с одним java-файлом, если вы ищете встраиваемое решение и не слишком беспокоитесь о производительности (хотя я не тестировал ее в этом отношении).

Это мульти-лицензионные EPL , LGPL и MPL .

В его документации также есть альтернативы, которые стоит проверить (помимо DBCP и C3P0):

Матье
источник