Skip to content

Commit 8ed0001

Browse files
committed
Modifica la implementación de ConnectionPool
1 parent 4c57d34 commit 8ed0001

File tree

3 files changed

+115
-113
lines changed

3 files changed

+115
-113
lines changed

source/03.xml/01.jaxp.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ construir primero un |DOM| y luego escribirlo a un archivo.
178178

179179
Generación del |DOM|
180180
--------------------
181-
Podemos tomar uno ya existente resultado de haber leído una archivo previo o
181+
Podemos tomar uno ya existente resultado de haber leído un archivo previo o
182182
crearlo *ex novo*:
183183

184184
.. code-block:: java

source/04.conector/10.extras.rst

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,24 @@ De este modo, para crear un *pool* con HikariCP_ basta con hacer lo siguiente\ [
2828
.. code-block:: java
2929
3030
// Pool de conexiones de una base SQLite en memoria.
31-
ConnectionPool pool = PoolConnection.getInstance("jdbc:sqlite:file::memory:?cache=shared");
32-
DataSource ds = pool.getDataSource();
33-
Connection conn = pool.getConnection(); // o ds.getConnection()
31+
DataSource ds = PoolConnection.getInstance("jdbc:sqlite:file::memory:?cache=shared");
32+
Connection conn = ds.getConnection();
3433
3534
Lo interesante de la clase, además de que simplifica la creación del *pool*, es que
3635
usa un `patrón Singleton`_, de manera que si intentamos crear un pool con los
37-
mismos parámetros, devolverá el pool ya creado y no otro distinto:
36+
mismos parámetros, genera una excepción:
3837

3938
.. code-block:: java
4039
4140
ConnectionPool pool1 = PoolConnection.getInstance("jdbc:sqlite:file::memory:?cache=shared");
42-
ConnectionPool pool2 = PoolConnection.getInstance("jdbc:sqlite:file::memory:?cache=shared");
43-
pool1 == pool2; // true
41+
ConnectionPool pool2 = PoolConnection.getInstance("jdbc:sqlite:file::memory:?cache=shared"); // IllegalStateException
4442
ConnectionPool pool3 = PoolConnection.getInstance();
4543
pool1 == pool3; // true
4644
ConnectionPool pool4 = PoolConnection.getInstance("jdbc:sqlite:caca.db");
4745
pool1 == pool4; // false
48-
ConnectionPool pool5 = PoolConnection.getInstance(); // IllegalArgumentException (hay dos, ¿cuál?)
46+
ConnectionPool pool5 = PoolConnection.getInstance(); // IllegalArgumentException (hay dos, ¿cuál es?)
4947
50-
.. warning:: Obsérvese la |URL| que se ha utilizado en los ejemplos. En el caso
48+
.. caution:: Obsérvese la |URL| que se ha utilizado en los ejemplos. En el caso
5149
particular de *SQLite*, para que las distintas conexiones del *pool* abran
5250
conexión a la misma base de datos en memoria, no basta con que la ruta sea
5351
:file:`:memory:`, sino que ha de usarse :file:`file::memory:?cache=shared`.
@@ -224,7 +222,7 @@ es descomponerlas primero. Para ello podemos optar por dos estrategias:
224222
<dependency>
225223
<groupId>com.github.sio2sio2</groupId>
226224
<artifactId>sqlutils</artifactId>
227-
<version>1.7.0</version>
225+
<version>2.0.1</version>
228226
</dependency>
229227
</dependencies>
230228
Lines changed: 107 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,108 @@
1-
package edu.acceso.borrarlo.backend;
2-
3-
import java.sql.Connection;
4-
import java.sql.SQLException;
5-
import java.util.HashMap;
6-
import java.util.Map;
7-
import java.util.Objects;
8-
import java.util.stream.Collectors;
9-
10-
import com.zaxxer.hikari.HikariConfig;
11-
import com.zaxxer.hikari.HikariDataSource;
12-
13-
/** Genera conexiones a la base de datos incluidas en un pool de conexiones */
14-
public class ConnectionPool implements AutoCloseable {
15-
16-
private static Map<Integer, ConnectionPool> instances = new HashMap<>();
17-
private final HikariDataSource ds;
18-
public static short maxConnections = 10;
19-
public static short minConnections = 1;
20-
21-
private ConnectionPool(String url, String user, String password) {
22-
HikariConfig hconfig = new HikariConfig();
23-
hconfig.setJdbcUrl(url);
24-
hconfig.setUsername(user);
25-
hconfig.setPassword(password);
26-
// Mínimo y máximo de conexiones.
27-
hconfig.setMaximumPoolSize(maxConnections);
28-
hconfig.setMinimumIdle(minConnections);
29-
ds = new HikariDataSource(hconfig);
30-
}
31-
32-
/**
33-
* Genera un pool de conexiones o reaprovecha uno ya creado
34-
* si coinciden los parámetros de creación.
35-
* @param url URL de la base de datos.
36-
* @param user Usuario de conexión
37-
* @param password Contraseña de conexión
38-
* @return El pool de conexiones
39-
*/
40-
public static ConnectionPool getInstance(String url, String user, String password) {
41-
int hashCode = Objects.hash(url, user, password);
42-
ConnectionPool instance = instances.get(hashCode);
43-
if(instance == null || instance.getDataSource().isClosed()) {
44-
instance = new ConnectionPool(url, user, password);
45-
instances.put(hashCode, instance);
46-
}
47-
return instance;
48-
}
49-
50-
/**
51-
* Genera un pool de conexiones o reaprovecha uno ya creado
52-
* si ya se creo uno con la URL suministrada.
53-
* @param url La URL de conexión.
54-
* @return El pool de conexiones.
55-
*/
56-
public static ConnectionPool getInstance(String url) {
57-
return ConnectionPool.getInstance(url, null, null);
58-
}
59-
60-
/**
61-
* Devuelve un pool de conexiones cuando sólo hay un candidato posible.
62-
* Como efecto secundario, elimina los pools cuyo DataSource esté cerrado.
63-
* @return El pool de conexiones.
64-
*/
65-
public static ConnectionPool getInstance() {
66-
ConnectionPool.clear();
67-
switch(instances.size()) {
68-
case 1:
69-
ConnectionPool instance = instances.values().iterator().next();
70-
if(instance.isActive()) return instance;
71-
else instances.clear();
72-
case 0:
73-
throw new IllegalArgumentException("No hay definido ningún pool activo");
74-
default:
75-
throw new IllegalArgumentException("Ambiguo: hay definidos varios pools");
76-
}
77-
}
78-
79-
/**
80-
* Elimina los pools cuyos DataSource estén cerrados.
81-
*/
82-
public static void clear() {
83-
instances = instances.entrySet()
84-
.stream().filter(e -> e.getValue().isActive())
85-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
86-
}
87-
88-
public Connection getConnection() throws SQLException {
89-
return ds.getConnection();
90-
}
91-
92-
public HikariDataSource getDataSource() {
93-
return ds;
94-
}
95-
96-
public boolean isActive() {
97-
return !ds.isClosed();
98-
}
99-
100-
@Override
101-
public void close() {
102-
ds.close();
103-
}
1+
package edu.acceso.sqlutils;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Objects;
6+
import java.util.stream.Collectors;
7+
8+
import com.zaxxer.hikari.HikariConfig;
9+
import com.zaxxer.hikari.HikariDataSource;
10+
11+
/**
12+
* Pool de conexiones para manejar múltiples conexiones a una base de datos.
13+
* Utiliza HikariCP como proveedor de conexión y el patrón Singleton
14+
* para garantizar que solo haya una instancia por combinación de URL, usuario y contraseña.
15+
*/
16+
public class ConnectionPool {
17+
18+
/** Mapa de instancias de ConnectionPool para implementar el patrón Singleton ampliado */
19+
private static Map<Integer, HikariDataSource> instances = new HashMap<>();
20+
/** Número máximo de conexiones en el pool */
21+
public static short maxConnections = 10;
22+
/** Número mínimo de conexiones en el pool */
23+
public static short minConnections = 1;
24+
25+
/**
26+
* Crea un {@link HikariDataSource} con la configuración dada.
27+
* @param url URL de la base de datos.
28+
* @param user Usuario de conexión
29+
* @param password Contraseña de conexión
30+
*/
31+
private static HikariDataSource createHikariDataSource(String url, String user, String password) {
32+
HikariConfig hconfig = new HikariConfig();
33+
hconfig.setJdbcUrl(url);
34+
hconfig.setUsername(user);
35+
hconfig.setPassword(password);
36+
// Mínimo y máximo de conexiones.
37+
hconfig.setMaximumPoolSize(maxConnections);
38+
hconfig.setMinimumIdle(minConnections);
39+
40+
return new HikariDataSource(hconfig);
41+
}
42+
43+
/**
44+
* Genera y almacena una fuente de datos HikariCP con la configuración dada.
45+
* Si los parámetros de configuración coinciden, genera una excepción
46+
* @param url URL de la base de datos.
47+
* @param user Usuario de conexión
48+
* @param password Contraseña de conexión
49+
* @return La fuente de datos HikariCP.
50+
* @throws IllegalArgumentException Si ya existe un pool con la configuración proporcionada.
51+
*/
52+
public static HikariDataSource getInstance(String url, String user, String password) {
53+
int hashCode = Objects.hash(url, user, password);
54+
HikariDataSource instance = instances.get(hashCode);
55+
if(instance == null || instance.isClosed()) {
56+
instance = createHikariDataSource(url, user, password);
57+
instances.put(hashCode, instance);
58+
return instance;
59+
}
60+
else throw new IllegalArgumentException("Ya existe un pool con la configuración proporcionada");
61+
}
62+
63+
/**
64+
* Devuelve un {@link HikariDataSource} cuando no son necesarios usuario ni contraseña.
65+
* @param url La URL de conexión.
66+
* @return La fuente de datos HikariCP.
67+
*/
68+
public static HikariDataSource getInstance(String url) {
69+
return ConnectionPool.getInstance(url, null, null);
70+
}
71+
72+
/**
73+
* Devuelve un pool de conexiones cuando sólo hay un candidato posible.
74+
* Como efecto secundario, elimina los pools cuyo DataSource esté cerrado.
75+
* @return La fuente de datos HikariCP.
76+
* @throws IllegalArgumentException Si no hay ningún pool activo o si hay varios candidatos.
77+
*/
78+
public static HikariDataSource getInstance() {
79+
ConnectionPool.clear();
80+
switch(instances.size()) {
81+
case 1:
82+
HikariDataSource instance = instances.values().iterator().next();
83+
if(!instance.isClosed()) return instance;
84+
else instances.clear();
85+
case 0:
86+
throw new IllegalArgumentException("No hay definido ningún pool activo");
87+
default:
88+
throw new IllegalArgumentException("Ambiguo: hay definidos varios pools");
89+
}
90+
}
91+
92+
/**
93+
* Elimina los DataSources cerrados del mapa de instancias.
94+
*/
95+
public static void clear() {
96+
instances = instances.entrySet()
97+
.stream().filter(e -> !e.getValue().isClosed())
98+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
99+
}
100+
101+
/**
102+
* Cierra todos los pools de conexiones y elimina todas las instancias.
103+
*/
104+
public static void reset() {
105+
instances.values().forEach(HikariDataSource::close);
106+
instances.clear();
107+
}
104108
}

0 commit comments

Comments
 (0)