una - integrar java con mysql
¿Cómo establecer un grupo de conexiones en JDBC? (13)
¿Alguien puede proporcionar ejemplos o enlaces sobre cómo establecer un conjunto de conexiones JDBC?
Al buscar en google, veo muchas maneras diferentes de hacerlo y es bastante confuso.
En definitiva, necesito el código para devolver un objeto java.sql.Connection
, pero estoy teniendo problemas para comenzar ... cualquier sugerencia es bienvenida.
Actualización: ¿ javax.sql
o java.sql
tienen implementaciones de conexión agrupadas? ¿Por qué no sería mejor usar estos?
HikariCP
Es moderno, rápido, simple. Lo uso para cada nuevo proyecto. Prefiero mucho más de C3P0, no conozco demasiado bien las otras piscinas.
A fines de 2017, Proxool, BoneCP, C3P0, DBCP están prácticamente desaparecidos en este momento. HikariCP (creado en 2012) parece prometedor, le quita las puertas a cualquier otra cosa que yo sepa. http://www.baeldung.com/hikaricp
Proxool tiene una serie de problemas:
- Bajo carga pesada puede exceder el número máximo de conexiones y no regresar por debajo del máximo
- Se las arregla para no volver a las conexiones mínimas incluso después de que las conexiones caduquen
- Puede bloquear todo el grupo (y todos los hilos del servidor / cliente) si tiene problemas para conectarse a la base de datos durante el hilo de HouseKeeper (no utiliza .setQueryTimeout)
- El subproceso HouseKeeper, aunque tiene un bloqueo de grupo de conexiones para su proceso, solicita que el subproceso Prototyper vuelva a crear las conexiones (barrido) que pueden dar como resultado una condición / bloqueo de carrera. En estas llamadas a métodos, el último parámetro siempre debe ser sweep: falso durante el ciclo, solo sweep: true debajo de él.
- HouseKeeper solo necesita el barrido PrototypeController al final y tiene más [mencionado arriba]
- El hilo de HouseKeeper comprueba si hay pruebas de conexiones antes de ver qué conexiones pueden haber expirado [existe el riesgo de probar la conexión caducada que puede romperse / terminar a través de otros tiempos de espera en DB en el cortafuegos, etc.]
- El proyecto tiene un código sin terminar (propiedades que están definidas pero no se actúa sobre ellas)
- La vida máxima de conexión predeterminada si no está definida es de 4 horas (excesiva)
- El hilo de HouseKeeper se ejecuta cada cinco segundos por grupo (excesivo)
Puede modificar el código y hacer estas mejoras. Pero como fue creado en 2003 y actualizado en 2008, le faltan casi 10 años de mejoras java que utilizan soluciones como hikaricp.
Apache Commons tiene una biblioteca para ese propósito: DBCP . A menos que tenga requisitos extraños en sus piscinas, usaría una biblioteca, ya que es más complicado y más sutil de lo que cabría esperar.
Como respondieron otros, probablemente estés satisfecho con DBCP o c3p0 . Ambos son populares y funcionan bien.
En cuanto a tu duda
¿Javax.sql o java.sql no tienen implementaciones de conexión agrupadas? ¿Por qué no sería mejor usar estos?
No proporcionan implementaciones, sino interfaces y algunas clases de soporte, solo revelentes para los programadores que implementan bibliotecas de terceros (grupos o controladores). Normalmente ni siquiera miras eso. Su código debería tratar las conexiones de su grupo de servidores de la misma manera que eran conexiones "simples", de forma transparente.
Debes considerar usar UCP. Universal Connection Pool (UCP) es un grupo de conexiones Java. Es un grupo de conexiones rico en funciones y está estrechamente integrado con las Real Application Clusters (RAC) de Oracle, las bases de datos ADG y DG.
Consulte esta page para obtener más detalles sobre UCP.
En el servidor de aplicaciones que utilizamos donde trabajo (Oracle Application Server 10g, según recuerdo), el servidor de aplicaciones se ocupa de la agrupación. Recuperamos un javax.sql.DataSource
usando una búsqueda JNDI con un javax.sql.InitialContext
.
se hace 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, se copia de esta documentación ).
No reinventar la rueda.
Pruebe uno de los componentes de terceros fácilmente disponibles:
Apache DBCP viene con un ejemplo diferente sobre cómo configurar un pooling javax.sql.DataSource . Aquí hay una sample que puede ayudarlo a comenzar.
Por lo general, si necesita un grupo de conexiones, está escribiendo una aplicación que se ejecuta en un entorno administrado, es decir, que se ejecuta dentro de un servidor de aplicaciones. Si este es el caso, asegúrese de verificar qué recursos de agrupación de conexiones proporciona su servidor de aplicaciones antes de probar cualquier otra opción.
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 se está ejecutando dentro de un servidor de aplicaciones, recomendaría el DBCP . Se usa ampliamente y proporciona toda la funcionalidad básica de agrupamiento que la mayoría de las aplicaciones requieren.
Si necesita un grupo de conexión independiente, mi preferencia es C3P0 sobre DBCP (que he mencionado en esta respuesta anterior ), tuve demasiados problemas con DBCP con mucha carga. Usar C3P0 es muy simple. De la documentation :
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 utilizar el grupo de conexiones integrado que proporciona. En ese caso, deberá configurarlo (consulte la documentación de su servidor de aplicaciones) y recuperar un DataSource a través de JNDI:
DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Yo recomendaría usar la biblioteca DBCP . Hay numerosos examples enumerados sobre cómo usarlo, aquí está el enlace al movimiento simple . El uso es muy simple:
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 perder recursos, también puede leer esta página de Wikipedia .
MiniConnectionPoolManager
es una implementación de un archivo java, si está buscando una solución incrustable y no está demasiado preocupado por el rendimiento (aunque no lo he probado en ese sentido).
Es multi licencia de EPL , LGPL y MPL .
Su documentación también ofrece alternativas que vale la pena verificar (además de DBCP y C3P0):
Piscina
- Pooling Mechanism es la forma de crear los objetos por adelantado. Cuando una clase está cargada
- Mejora el
performance
la aplicación [Al usar el mismo objeto para realizar cualquier acción en Object-Data] y lamemory
[asignar y desasignar muchos objetos crea una sobrecarga de administración de memoria significativa]. - La limpieza de objetos no es necesaria ya que estamos utilizando el mismo objeto, reduciendo la carga de recolección de basura.
«Puesta en común [grupo de Object
, conjunto constante de String
, conjunto de Thread
, grupo de conexiones]
Grupo de constante de cadena
- El grupo literal String mantiene solo una copia de cada valor de cadena distinto. que debe ser inmutable
- Cuando se invoca el método interno, comprueba la disponibilidad del objeto con el mismo contenido en el grupo utilizando el método equals. «Si String-copy está disponible en Pool, entonces 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));
}
}
DBCP2
conexión que utiliza el Driver tipo 4 con bibliotecas de terceros [ 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 de grupo de conexiones, cuando se carga la clase, se obtienen los objetos de physical JDBC connection
y se proporciona un objeto de conexión física envuelto al usuario. PoolableConnection
es un contenedor alrededor de la conexión real.
-
getConnection()
elige uno de los enlaces de conexión objectpool conexión y lo devuelve. -
close()
lugar de cerrar, devuelve la conexión envuelta al grupo.
Ejemplo: usando el conjunto de conexiones ~ DBCP2 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" predeterminado 8 horas] para reabrir la conexión con el DB subyacente.
Puede hacer esto para probar cada conexión estableciendo testOnBorrow = true y validationQuery = "SELECT 1" y no use el servidor de autoReconnect para MySQL ya que está en desuso. 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(); }
}
Ver estos también:
Vibur DBCP es otra biblioteca para ese propósito. Varios ejemplos que muestran cómo configurarlo para usar con Hibernate, Spring + Hibernate o programáticamente, se pueden encontrar en su sitio web: http://www.vibur.org/
Además, vea la exención de responsabilidad here .