Como estabelecer um pool de conexão no JDBC?

Alguém pode fornecer exemplos ou links sobre como estabelecer um pool de conexão JDBC?

A partir da pesquisa no google, vejo muitas maneiras diferentes de fazer isso e é bastante confuso.

Em última análise, eu preciso do código para retornar um object java.sql.Connection , mas estou tendo problemas para começar .. qualquer sugestão é bem-vinda.

Atualização: javax.sql ou java.sql tem implementações de conexão em pool? Por que não seria melhor usá-los?

Se você precisa de um pool de conexão independente, minha preferência vai para o C3P0 sobre o DBCP (que eu mencionei nesta resposta anterior ), eu tive problemas demais com o DBCP sob carga pesada. Usando o C3P0 é muito simples. Da documentação :

 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 

Mas se você estiver executando em um servidor de aplicativos, recomendo usar o pool de conexão interno que ele fornece. Nesse caso, você precisará configurá-lo (consulte a documentação do seu servidor de aplicativos) e recuperar um DataSource via JNDI:

 DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS"); 

Geralmente, se você precisar de um pool de conexão, você está escrevendo um aplicativo que é executado em algum ambiente gerenciado, ou seja, você está executando dentro de um servidor de aplicativos. Se este for o caso, certifique-se de verificar quais resources de pool de conexão seu servidor de aplicativos fornece antes de tentar qualquer outra opção.

A solução pronta para uso será a melhor integrada aos demais resources dos servidores de aplicativos. Se, no entanto, você não estiver executando em um servidor de aplicativos, recomendo o componente DBCP do Apache Commons . É amplamente utilizado e fornece toda a funcionalidade básica de pooling que a maioria das aplicações requer.

Eu recomendaria usar a biblioteca commons-dbcp . Existem inúmeros exemplos listados em como usá-lo, aqui está o link para o movimento simples . O uso é muito simples:

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

Você só precisa criar a fonte de dados uma vez, portanto, leia a documentação se não souber como fazer isso. Se você não está ciente de como escrever corretamente instruções JDBC para não vazar resources, você também pode querer ler esta página da Wikipedia .

Não reinvente a roda.

Experimente um dos componentes de terceiros disponíveis:

  • Apache DBCP – Este é usado internamente pelo Tomcat, e por você mesmo.
  • c3p0

O Apache DBCP vem com um exemplo diferente de como configurar um conjunto javax.sql.DataSource . Aqui está uma amostra que pode ajudá-lo a começar.

HikariCP

É moderno, é rápido, é simples. Eu uso para cada novo projeto. Eu prefiro muito mais que C3P0, não conheço as outras piscinas muito bem.

No servidor de aplicativos, usamos onde eu trabalho (Oracle Application Server 10g, se bem me lembro), o pool é tratado pelo servidor de aplicativos. Nós recuperamos um javax.sql.DataSource usando uma consulta JNDI com um javax.sql.InitialContext .

é feito algo parecido com isto

 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()); } 

(Nós não escrevemos este código, ele é copiado desta documentação .)

Como foi respondido por outros, você provavelmente ficará satisfeito com o Apache Dbcp ou c3p0 . Ambos são populares e funcionam bem.

Em relação a sua dúvida

Não javax.sql ou java.sql têm implementações de conexão em pool? Por que não seria melhor usá-los?

Eles não fornecem implementações, interfaces e algumas classs de suporte, apenas reveladoras para os programadores que implementam bibliotecas de terceiros (pools ou drivers). Normalmente você nem olha para isso. Seu código deve lidar com as conexões do seu pool, da mesma forma que eram conexões “simples”, de maneira transparente.

Vibur DBCP é outra biblioteca para esse propósito. Vários exemplos mostrando como configurá-lo para uso com o Hibernate, Spring + Hibernate, ou programaticamente, podem ser encontrados em seu site: http://www.vibur.org/

Além disso, veja o aviso aqui .

Piscina

  • O mecanismo de pooling é a maneira de criar os objects com antecedência. Quando uma class é carregada.
  • Ele melhora o performance do aplicativo [usando novamente o mesmo object para executar qualquer ação em Object-Data] e memory [alocar e desalocar muitos objects cria uma sobrecarga de gerenciamento de memory significativa].
  • A limpeza de objects não é necessária, pois estamos usando o mesmo object, reduzindo a carga da garbage collection.

«Pooling [pool de Object , pool constante de String , pool de Thread , pool de conexões]

Piscina constante de cordas

  • O conjunto literal de cadeias mantém apenas uma cópia de cada valor de cadeia distinto. que deve ser imutável.
  • Quando o método interno é chamado, ele verifica a disponibilidade do object com o mesmo conteúdo no pool usando o método equals. «Se String-copy estiver disponível no Pool, então retorna a referência. «Caso contrário, o object String é adicionado ao pool e retorna a referência.

Exemplo: String para verificar o Unique Object do pool.

 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)); } } 

Pool de conexão usando o Driver Type-4 usando bibliotecas de terceiros [ DBCP2 , c3p0 , Tomcat JDBC ]

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

No mecanismo do conjunto de conexões, quando a class é carregada, obtém os objects de physical JDBC connection e fornece um object de conexão física encapsulado ao usuário. PoolableConnection é um wrapper em torno da conexão real.

  • getConnection() seleciona um dos formulários de conexão empacotada livre do conjunto de objects de conexão e os retorna.
  • close() invés de fechá-lo retorna a conexão empacotada de volta ao pool.

Exemplo: Usando o Conjunto de Conexões DBCP2 com 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::::: jdbc: oracle :thin:@localhost:1521:myDBName ://localhost:3306/myDBName :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 : 

Aplicação Web : Para evitar problemas de conexão quando todas as conexões estão fechadas [padrão do MySQL “wait_timeout” padrão de 8 horas] para reabrir a conexão com o database subjacente.

Você pode fazer isso para testar todas as conexões definindo testOnBorrow = true e validationQuery = “SELECT 1” e não usar autoReconnect para o servidor MySQL, pois ele é obsoleto. questão

 ===== ===== context.xml ===== =====      ===== ===== web.xml ===== =====  DB Connection jdbc/MyAppDB javax.sql.DataSource Container  ===== ===== 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(); } } 

Veja estes também:

  • am-i-using-jdbc-connection-pooling
  • configurando-jdbc-pool-alta-simultaneidade

O Apache Commons tem uma biblioteca para essa finalidade: DBCP . A menos que você tenha requisitos estranhos em torno de seus pools, eu usaria uma biblioteca, pois ela seria mais complicada e mais sutil do que você esperaria.

No final de 2017, Proxool, BoneCP, C3P0 e DBCP estão praticamente desativados neste momento. HikariCP (criado em 2012) parece promissor, tira as portas de qualquer coisa que eu saiba. http://www.baeldung.com/hikaricp

Proxool tem vários problemas:
– Sob carga pesada pode exceder o número máximo de conexões e não retornar abaixo do máximo
– Consegue não retornar a conexões mínimas mesmo após as conexões expirarem
– Pode bloquear todo o pool (e todos os threads do servidor / cliente) se tiver problemas para se conectar ao database durante o thread do HouseKeeper (não usa .setQueryTimeout)
– O encadeamento HouseKeeper, ao ter o bloqueio do conjunto de conexões para seu processo, solicita que o encadeamento do Prototyper recrie conexões (varredura), o que pode resultar em condição / bloqueio de corrida. Nestas chamadas de método o último parâmetro deve sempre ser sweep: false durante o loop, somente sweep: true abaixo dele.
– O HouseKeeper só precisa da varredura do PrototypeController no final e tem mais [mencionado acima]
– A thread do HouseKeeper verifica o teste das conexões antes de ver quais conexões podem estar vencidas [algum risco de testar a conexão expirada que pode ser interrompida / terminada através de outros timeouts para o DB no firewall, etc.]
– O projeto tem código inacabado (propriedades que são definidas, mas não são postas em prática)
– A vida máxima da conexão padrão, se não definida, é de 4 horas (excessiva)
– O encadeamento HouseKeeper é executado a cada cinco segundos por pool (excessivo)

Você pode modificar o código e fazer essas melhorias. Mas como foi criado em 2003 e atualizado em 2008, faltam quase 10 anos de melhorias no Java que soluções como o hikaricp utilizam.

Você deve considerar o uso do UCP. O Universal Connection Pool (UCP) é um pool de conexão Java. É um conjunto de conexões rico em resources e totalmente integrado aos bancos de dados do Real Application Clusters (RAC), ADG e DG da Oracle.

Consulte esta página para mais detalhes sobre o UCP.

MiniConnectionPoolManager é uma implementação de um arquivo java, se você estiver procurando por uma solução incorporável e não estiver muito preocupado com performances (embora eu não tenha testado a respeito).

É multi-licenciado EPL , LGPL e MPL .

Sua documentação também oferece alternativas que valem a pena checar (além do DBCP e do C3P0):

  • Proxool
  • BoneCP
  • Pool de Conexões Tomcat JDBC