¿Cómo establecer un grupo de conexiones en JDBC?

111

¿Alguien puede proporcionar ejemplos o enlaces sobre cómo establecer un grupo de conexiones JDBC?

Al buscar en Google, veo muchas formas diferentes de hacer esto y es bastante confuso.

En última instancia, necesito el código para devolver un java.sql.Connectionobjeto, pero tengo problemas para comenzar ... cualquier sugerencia es bienvenida.

Actualización: ¿No tiene implementaciones de conexión agrupadas javax.sqlo no las java.sqltiene? ¿Por qué no sería mejor usar estos?

llm
fuente
8
No, JDBC estándar no proporciona agrupación de conexiones. Necesita una biblioteca separada para eso. La mayoría de los servidores de aplicaciones y contenedores de servlets tienen grupos de conexiones incluidos. Además, las implementaciones de JPA también suelen proporcionar implementaciones.
Will Hartung
3
Una actualización para los usuarios de Java de hoy en día. JDBC 3.0+ (que creo que se usa en Java 6) tiene una implementación para conexiones de base de datos agrupadas. Java 7 usa JDBC 4 y Java 8 JDBC 4.1.
BRasmussen
1
Con respecto a la API JDBC 3.0 para la agrupación de conexiones: progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Arto Bendiken

Respuestas:

102

Si necesita un grupo de conexiones independiente, mi preferencia es C3P0 sobre DBCP (que mencioné en esta respuesta anterior ), simplemente tuve demasiados problemas con DBCP bajo carga pesada. Usar C3P0 es muy simple. De la documentación :

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 

Pero si está ejecutando dentro de un servidor de aplicaciones, le recomendaría usar el grupo de conexiones incorporado que proporciona. En ese caso, deberá configurarlo (consulte la documentación de su servidor de aplicaciones) y recuperar una fuente de datos a través de JNDI:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Pascal Thivent
fuente
1
Lo mismo ocurre con eso. He estado observando el interbloqueo de DBCP bajo una carga durante años. Versión tras versión.
Vasiliy
sí, pero también C3P0, he tenido la mejor experiencia con BoneCP
Nicolas Mommaerts
1
Parece que BoneCP ha quedado obsoleto en favor de HikariCP . HikariCP también se menciona en una respuesta a continuación .
kaartic
19

Por lo general, si necesita un grupo de conexiones, está escribiendo una aplicación que se ejecuta en algún entorno administrado, es decir, se está ejecutando dentro de un servidor de aplicaciones. Si este es el caso, asegúrese de verificar qué funciones de agrupación de conexiones proporciona su servidor de aplicaciones antes de probar otras opciones.

La solución lista para usar será la mejor integrada con el resto de las instalaciones de los servidores de aplicaciones. Sin embargo, si no está ejecutando dentro de un servidor de aplicaciones, le recomendaría el componente Apache Commons DBCP . Se utiliza ampliamente y proporciona todas las funciones básicas de agrupación que requieren la mayoría de las aplicaciones.

Tendayi Mawushe
fuente
18

HikariCP

Es moderno, es rápido, es simple. Lo uso para cada nuevo proyecto. Lo prefiero mucho al C3P0, no conozco demasiado bien los otros grupos.

tobijdc
fuente
18

No reinventes la rueda.

Pruebe uno de los componentes de terceros disponibles:

Apache DBCP viene con un ejemplo diferente sobre cómo configurar una agrupación javax.sql.DataSource . Aquí hay una muestra que puede ayudarlo a comenzar.

Alexander Pogrebnyak
fuente
1
Se llama C3P0. Por cierto, tiene más rendimiento que DBCP en entornos multiproceso, ya que DBCP bloquea el acceso a un solo subproceso.
BalusC
@BalusC. Gracias por la corrección, me disclecsiasuperó. Puede ver que el enlace es correcto. :)
Alexander Pogrebnyak
1
@Mudassir. Recomendaría buscar un reemplazo directo para DBCP contribuido a Tomcat desde Spring -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… . No necesita todo el servidor Tomcat para usarlo, solo un solo frasco tomcat-jdbc. Puede obtenerlo en Maven Central -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Alexander Pogrebnyak
@AlexanderPogrebnyak: Gracias Alexander, es muy amable de tu parte. Estoy pensando en utilizar CP en un servicio web de Axis. Pensará en tu sugerencia. - Mudassir hace 7 minutos
Mudassir
17

Recomendaría usar la biblioteca commons-dbcp . Hay numerosos ejemplos enumerados sobre cómo usarlo, aquí está el enlace al movimiento simple . El uso es muy sencillo:

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

Solo necesita crear la fuente de datos una vez, así que asegúrese de leer la documentación si no sabe cómo hacerlo. Si no sabe cómo escribir correctamente las declaraciones JDBC para no filtrar recursos, también puede leer esta página de Wikipedia .

Eric Hauser
fuente
8
¿Esto realmente crea un grupo de conexiones?
llm
@llm ¡Seguro! La javax.sql.DataSourcedefinición de la interfaz contiene una implementación de "Connection pooling". (Además, creo que ya sabes qué es una interfaz JDBC)
Eddy
7

En el servidor de aplicaciones que usamos donde trabajo (Oracle Application Server 10g, según recuerdo), el servidor de aplicaciones maneja la agrupación. Recuperamos unjavax.sql.DataSource uso de una búsqueda JNDI con unjavax.sql.InitialContext .

ha hecho algo como esto

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

(No escribimos este código, está copiado de esta documentación ).

Señor de poder
fuente
5

Piscina

  • Pooling Mechanism es la forma de crear los Objetos por adelantado. Cuando se carga una clase.
  • Mejora la aplicación performance[Al volver a usar los mismos objetos para realizar cualquier acción en los datos de objeto] y memory[asignar y desasignar muchos objetos crea una sobrecarga significativa de administración de memoria].
  • La limpieza de objetos no es necesaria ya que estamos usando el mismo objeto, lo que reduce la carga de recolección de basura.

«Agrupación [ Objectgrupo, grupo Stringconstante, grupo Thread, grupo de conexiones]

Grupo constante de cadena

  • El grupo de literales de cadena mantiene solo una copia de cada valor de cadena distinto. que debe ser inmutable.
  • Cuando se invoca el método interno, verifica la disponibilidad del objeto con el mismo contenido en el grupo utilizando el método equals. «Si String-copy está disponible en el Pool, devuelve la referencia. «De lo contrario, el objeto String se agrega al grupo y devuelve la referencia.

Ejemplo: cadena para verificar el objeto único del grupo.

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

Agrupación de conexiones utilizando Tipo 4- Conductor uso de las bibliotecas 3 ª Parte [ 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

En el mecanismo del grupo de conexiones, cuando se carga la clase, obtiene los physical JDBC connectionobjetos y proporciona un objeto de conexión física envuelto al usuario. PoolableConnectiones un envoltorio alrededor de la conexión real.

  • getConnection()elija una de las conexiones envueltas libres del grupo de objetos de conexión y lo devuelva.
  • close() en lugar de cerrar, devuelve la conexión envuelta al grupo.

Ejemplo: uso de ~ DBCP2 Connection Pool con 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    :

Aplicación web : para evitar problemas de conexión cuando todas las conexiones están cerradas [MySQL "wait_timeout" por defecto 8 horas] para volver a abrir la conexión con la base de datos subyacente.

Puede hacer esto para probar todas las conexiones configurando testOnBorrow = true y validationQuery = "SELECT 1" y no use autoReconnect para el servidor MySQL, ya que está obsoleto. problema

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

Vea estos también:

Yash
fuente
En el ejemplo del grupo String Constant, entiendo cuando escribió "Si String-copy está disponible [.equals ()] en el Pool, entonces devuelve la referencia.« De lo contrario, el objeto String se agrega al grupo y devuelve la referencia ". Pero en el public class StringPoolTestsolo tiene 2 métodos anulados para que no devuelvan nada. ¿Ese código realmente pasa por el proceso de administrar el grupo de cadenas? Ni siquiera parece utilizar ningún argumento.
jeffery_the_wind
@jeffery_the_wind: - es sólo para conocer el concepto de la piscina, piscina para cadena de verificación que acabo de utilizar hashCode, identityHashCode methodes . modificó el código ...
Yash
Lo siento, s1¿no está definido?
jeffery_the_wind
De acuerdo, solo quería asegurarme de que lo estaba viendo todo. Trabajaré en eso. Lo que necesitaré para algo más cercano a su ConnectionPoolClase. Muchas gracias.
jeffery_the_wind
5

A finales de 2017, Proxool, BoneCP, C3P0, DBCP están desaparecidos en su mayoría en este momento. HikariCP (creado en 2012) parece prometedor, rompe las puertas de cualquier otra cosa que yo sepa. http://www.baeldung.com/hikaricp

Proxool tiene una serie de problemas:
- Bajo una carga pesada puede exceder el número máximo de conexiones y no regresar por debajo del máximo
- Puede lograr no regresar a las conexiones mínimas incluso después de que expiren las conexiones
- Puede bloquear todo el grupo (y todos los hilos del servidor / cliente) si tiene problemas para conectarse a la base de datos durante el subproceso de HouseKeeper (no usa .setQueryTimeout)
- El subproceso de HouseKeeper, mientras tiene un bloqueo de grupo de conexiones para su proceso, solicita al subproceso de Prototyper que vuelva a crear conexiones (barrido) que pueden resultar en una condición de carrera / bloqueo. En estas llamadas a métodos, el último parámetro siempre debe ser sweep: false durante el ciclo, solo sweep: true debajo de él.
- HouseKeeper solo necesita el barrido único de PrototypeController al final y tiene más [mencionado anteriormente]
- El hilo HouseKeeper comprueba las conexiones antes de ver qué conexiones pueden estar caducadas [existe el riesgo de probar una conexión caducada que puede romperse / terminarse a través de otros tiempos de espera para la base de datos en el firewall, etc.]
- El proyecto tiene código sin terminar (propiedades que están definidas pero sin actuar)
- La vida útil máxima predeterminada de la conexión si no se define es de 4 horas (excesiva)
- El hilo de HouseKeeper se ejecuta cada cinco segundos por grupo (excesivo)

Puede modificar el código y realizar estas mejoras. Pero como fue creado en 2003 y actualizado en 2008, le faltan casi 10 años de mejoras de Java que utilizan soluciones como hikaricp.

bluejaguar
fuente
4

Como han respondido otros, probablemente estará satisfecho con Apache Dbcp o c3p0 . Ambos son populares y funcionan bien.

Sobre tu duda

¿No tienen javax.sql o java.sql implementaciones de conexiones agrupadas? ¿Por qué no sería mejor usar estos?

No proporcionan implementaciones, sino interfaces y algunas clases de soporte, solo revelado por los programadores que implementan bibliotecas de terceros (grupos o controladores). Normalmente ni siquiera miras eso. Su código debe tratar las conexiones de su grupo como si fueran conexiones "simples", de manera transparente.

Leonbloy
fuente
4

Vibur DBCP es otra biblioteca para ese propósito. En su sitio web se pueden encontrar varios ejemplos que muestran cómo configurarlo para usarlo con Hibernate, Spring + Hibernate o programáticamente: http://www.vibur.org/

Además, consulte el descargo de responsabilidad aquí .

Simeon Malchev
fuente
3

Apache Commons tiene una biblioteca para ese propósito: DBCP . A menos que tenga requisitos extraños alrededor de sus grupos, usaría una biblioteca, ya que seguramente será más complicado y sutil de lo que esperaría.

sblundy
fuente
1

Debería considerar el uso de UCP. Grupo de conexiones universal (UCP) es un grupo de conexiones de Java. Es un grupo de conexiones rico en características y está estrechamente integrado con las bases de datos Real Application Clusters (RAC), ADG, DG de Oracle.

Consulte esta página para obtener más detalles sobre UCP.

Nirmala
fuente