From f1058bad27bb9fb7ddd15c8f98961a3ab7f2cf8d Mon Sep 17 00:00:00 2001 From: Isaias Battaglia Date: Thu, 13 Aug 2026 14:31:23 -0300 Subject: [PATCH 1/3] Feature ETP-4296: Add guide for diagnosing idle in transaction connections Add a new how-to guide covering detection, root-cause investigation, and pool-level mitigation for Hibernate/DAL sessions left open outside DalFilter's lifecycle, which PostgreSQL reports as idle in transaction. Expand the external connection pool guide with the full list of pool properties and defaults referenced by the new guide, and register both pages in the nav (EN/ES). --- ...iagnose-idle-in-transaction-connections.md | 96 +++++++++++++++++++ .../how-to-use-an-external-connection-pool.md | 89 ++++++++++++++--- ...iagnose-idle-in-transaction-connections.md | 96 +++++++++++++++++++ .../how-to-use-an-external-connection-pool.md | 89 ++++++++++++++--- mkdocs.yml | 3 + 5 files changed, 349 insertions(+), 24 deletions(-) create mode 100644 docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md create mode 100644 docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md diff --git a/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md b/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md new file mode 100644 index 0000000000..10e8238910 --- /dev/null +++ b/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md @@ -0,0 +1,96 @@ +--- +title: How to Diagnose Idle in Transaction Connections +tags: + - Connection Pool + - Troubleshooting + - Database + - PostgreSQL + - Hibernate + - DAL +status: beta +--- + +# How to Diagnose Idle in Transaction Connections + +!!! example "IMPORTANT: THIS IS A BETA VERSION" + This page is under active development and may contain **unstable or incomplete features**. Use it **at your own risk**. + +## Overview + +Etendo serves most requests through `DalFilter`, which opens a Hibernate/DAL session at the start of the request and closes it once the response is sent. Custom servlets, processes, or webservice endpoints that call `OBDal.getInstance()` or open a `SessionHandler` session outside that lifecycle are responsible for closing the session themselves. + +A session that is never closed keeps its underlying JDBC connection checked out of the pool with an open transaction. PostgreSQL reports that connection as `idle in transaction`. Left unbounded, this blocks autovacuum on the tables the transaction touched, causes table bloat, and degrades database performance over time. Restarting Tomcat clears the pool and hides the symptom temporarily, which is why the underlying leak can go unnoticed for a while. + +## Detecting the Problem + +Query PostgreSQL for connections stuck in this state: + +```sql +SELECT pid, now() - query_start AS duration, state, LEFT(query, 80) AS query_snippet +FROM pg_stat_activity +WHERE state = 'idle in transaction'; +``` + +A growing number of rows that never clears until Tomcat restarts indicates a session that is not being closed somewhere in the request path. + +## Finding the Leak + +Review custom code paths that open a DAL or Hibernate session directly instead of relying on `DalFilter`. This is common in servlets that extend `HttpServlet` or `HttpBaseServlet` directly, bypassing the standard filter chain. Each of these paths must close its session explicitly in a `finally` block: + +```java +try { + // ... request processing that uses OBDal.getInstance() ... +} finally { + OBDal.getInstance().commitAndClose(); +} +``` + +Or, when using `SessionHandler` directly: + +```java +try { + // ... request processing ... +} finally { + SessionHandler.getInstance().commitAndClose(); +} +``` + +To confirm which code path is responsible before changing anything, enable abandoned-connection logging. This logs the stack trace of where a connection was borrowed once it has been checked out longer than expected, without closing anything: + +```properties title="gradle.properties" +db.pool.logAbandoned=true +db.pool.suspectTimeout= +``` + +Apply the change with: + +```bash +./gradlew setup +``` + +!!! warning + Logging abandoned connections adds overhead to every connection borrow, because a stack trace has to be generated. Use it to diagnose the leak, then disable it once the responsible code path is identified. + +## Mitigating at the Pool Level + +While the code fix is developed and rolled out, the connection pool can be configured to forcibly reclaim connections that have been checked out too long. Add the following properties to `gradle.properties`: + +```properties title="gradle.properties" +db.pool.removeAbandoned=true +db.pool.removeAbandonedTimeout= +``` + +Then apply the change: + +```bash +./gradlew setup +``` + +See [How to Use an External Connection Pool](how-to-use-an-external-connection-pool.md#pool-configuration) for the full reference of pool configuration properties. + +!!! warning + Set `removeAbandonedTimeout` well above the longest legitimate transaction or background process duration in the environment. Any operation still running past that timeout has its connection reclaimed while in use, which corrupts that operation. This setting is a temporary safety net, not a substitute for closing the session in code. + +--- + +This work is licensed under :material-creative-commons: :fontawesome-brands-creative-commons-by: :fontawesome-brands-creative-commons-sa: [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="_blank"} by [Futit Services S.L](https://etendo.software){target="_blank"}. diff --git a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 91f420d085..6cae399518 100644 --- a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -17,25 +17,90 @@ status: beta ## Overview -By default, Etendo uses two connection pools: +Etendo ships with the [Apache JDBC Connection Pool](https://github.com/etendosoftware/etendo_core/tree/main/modules_core/org.openbravo.apachejdbcconnectionpool){target="\_blank"} enabled by default, through the `org.openbravo.apachejdbcconnectionpool` core module. This module implements Etendo's `ExternalConnectionPool` abstraction on top of the [Apache Tomcat JDBC Connection Pool](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html){target="\_blank"}. No installation step is required: `Openbravo.properties` already sets -- Hibernate default connection pool for DAL-related queries -- [Apache DBCP](https://commons.apache.org/proper/commons-dbcp/){target="\_blank"} for the connections provided by the `ConnectionProviderImpl`. +```properties title="Openbravo.properties" +db.externalPoolClassName=org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool +``` -!!!info - It is possible to specify an external connection provider that Etendo will use to obtain the *JDBC connections*. For that, a module containing a subclass of `ExternalConnectionPool` needs to be installed, and the `db.externalPoolClassName` property has to be set in `gradle.properties` file. +Because the pool is already active on every installation, the work described on this page is tuning its properties — see [Pool Configuration](#pool-configuration) below. Changing `db.externalPoolClassName` to a different class only becomes necessary to plug in a **custom** external connection pool implementation instead of the bundled one; see [How to Create an External Connection Pool](how-to-create-an-external-connection-pool.md) for that scenario. + +Pool properties are set in `gradle.properties`. After adding or changing any of them, apply the change with: -## Example: Using the Apache JDBC Connection Pool +```bash +./gradlew setup +``` -The [Apache JDBC Connection Pool](https://github.com/etendosoftware/etendo_core/tree/main/modules_core/org.openbravo.apachejdbcconnectionpool){target="\_blank"} module core provides an implementation of the Apache JDBC Connection Pool. +This regenerates `Openbravo.properties`, which `JdbcExternalConnectionPool` reads at runtime to build the pool. -The `db.externalPoolClassName` property has to be set in `gradle.properties`. This module implements the external connection pool class in the `org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool` class, so this line should be added to `gralde.properties`: +## Pool Configuration -``` title="Gradle.properties" -db.externalPoolClassName=org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool +A fresh Etendo installation ships with the following properties already set: + +```properties title="Openbravo.properties (generated)" +db.pool.initialSize=1 +db.pool.minIdle=5 +db.pool.maxActive=10000 +db.pool.timeBetweenEvictionRunsMillis=60000 +db.pool.minEvictableIdleTimeMillis=120000 +db.pool.removeAbandoned=false +db.pool.testOnBorrow=true +db.pool.testWhileIdle=false +db.pool.testOnReturn=false +db.pool.validationQuery=SELECT 1 FROM DUAL +db.pool.validationInterval=30000 +db.pool.jmxEnabled=false ``` -This module contains a configuration file template: `modules_core/org.openbravo.apachejdbcconnectionpool/config/connectionPool.properties.template`. In order to customize the JDBC connection pool properties this file has to be copied to `modules_core/org.openbravo.apachejdbcconnectionpool/config/connectionPool.properties`. The user can then configure the pool properties according to his needs. Hints about how to configure this properties can be found [here](https://tomcat.apache.org/){target="\_blank"}. +Override any of them by setting the corresponding property in `gradle.properties`: + +| Property | Description | Default | +| --- | --- | --- | +| `db.pool.initialSize` | Connections established when the pool starts. Lowered automatically if it exceeds `db.pool.maxActive`. | `1` | +| `db.pool.minIdle` | Minimum established connections kept in the pool at all times. The idle pool does not shrink below this value during an eviction run, but it can still drop lower if `db.pool.validationQuery` fails and connections are closed. | `5` | +| `db.pool.maxActive` | Maximum active connections the pool can hand out at the same time. Kept high by default because capacity planning is delegated to the database; it should be at least as high as the database's own maximum connections. If lowered below that, `db.pool.maxWait` becomes relevant. | `10000` | +| `db.pool.timeBetweenEvictionRunsMillis` | How often (ms) the sweeper thread checks idle and abandoned connections. See [How does the sweeper thread work?](#how-does-the-sweeper-thread-work). Should not be set below `1000`. | `60000` | +| `db.pool.minEvictableIdleTimeMillis` | Minimum time (ms) a connection may sit idle before the sweeper evicts it. | `120000` | +| `db.pool.removeAbandoned` | If `true`, connections held longer than `db.pool.removeAbandonedTimeout` are forcibly reclaimed. | `false` | +| `db.pool.testOnBorrow` | Validates a connection before handing it out; drops and retries if invalid. Requires `db.pool.validationQuery` to be set. | `true` | +| `db.pool.testOnReturn` | Validates a connection when it is returned to the pool. | `false` | +| `db.pool.testWhileIdle` | Validates idle connections periodically. | `false` | +| `db.pool.validationQuery` | SQL used to validate a connection. Must not throw an exception. Required for `testOnBorrow`, `testOnReturn`, and `testWhileIdle` to have any effect. | `SELECT 1 FROM DUAL` | +| `db.pool.validationInterval` | Minimum milliseconds between validations of the same connection, to avoid redundant checks. | `30000` | +| `db.pool.jmxEnabled` | Exposes pool metrics through JMX. | `false` | + +The pool also supports the properties below. Etendo does not set a default for any of them — when a property is not set in `gradle.properties`, the underlying [Apache Tomcat JDBC Connection Pool](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html#Common_Attributes){target="\_blank"} default applies instead: + +| Property | Description | +| --- | --- | +| `db.pool.maxIdle` | Maximum idle connections kept in the pool when the sweeper is disabled. | +| `db.pool.maxWait` | Milliseconds the pool waits for a connection to be returned before throwing an exception, once `db.pool.maxActive` has been reached. | +| `db.pool.numTestsPerEvictionRun` | Number of connections examined in each sweeper run. | +| `db.pool.removeAbandonedTimeout` | Seconds a connection can be checked out before it is considered abandoned. Only relevant when `db.pool.removeAbandoned=true`. | +| `db.pool.testOnConnect` | Validates a connection right after it is physically created. | +| `db.pool.validatorClassName` | Custom validator class used instead of `db.pool.validationQuery`. | +| `db.pool.initSQL` | SQL executed once, right after a physical connection is created. | +| `db.pool.defaultAutoCommit` | Default auto-commit state of connections returned by the pool. | +| `db.pool.defaultReadOnly` | Default read-only state of connections returned by the pool. | +| `db.pool.defaultTransactionIsolation` | Default transaction isolation level of connections returned by the pool. | +| `db.pool.defaultCatalog` | Default catalog of connections returned by the pool. | +| `db.pool.connectionProperties` | Extra driver-specific connection properties, as a semicolon-separated list of `name=value` pairs. | +| `db.pool.accessToUnderlyingConnectionAllowed` | Allows retrieving the underlying physical connection through the pooled connection wrapper. | +| `db.pool.logAbandoned` | Logs the stack trace of where a connection was borrowed once it has been checked out longer than `db.pool.suspectTimeout`. Adds overhead to every borrow, since a stack trace has to be generated. | +| `db.pool.suspectTimeout` | Seconds a connection can be checked out before it is logged as suspect. Only relevant when `db.pool.logAbandoned=true`. Independent from `db.pool.removeAbandoned` — a suspect connection is only logged, not reclaimed. | +| `db.pool.name` | Name assigned to the pool, useful to tell pools apart when several are configured. | + +!!!info + Any of these properties can be scoped to a specific named pool — for example the read-only pool — by inserting the pool name after `db.`, e.g. `db.readonly.pool.maxActive`. A pool-specific value takes precedence over the default `db.pool.*` value for that pool; a pool that does not define its own value falls back to the default. + +### How does the sweeper thread work? + +The sweeper is the background thread that runs every `db.pool.timeBetweenEvictionRunsMillis` milliseconds to validate idle connections and check for abandoned ones. Whether it is enabled changes how the idle pool behaves: + +- **Sweeper disabled**: if the idle pool grows larger than `db.pool.maxIdle`, a connection is closed as soon as it is returned to the pool instead of being kept idle. +- **Sweeper enabled**: the number of idle connections can grow beyond `db.pool.maxIdle`, but shrinks back down to `db.pool.minIdle` once a connection has been idle longer than `db.pool.minEvictableIdleTimeMillis`. + +The full list of configurable Tomcat JDBC Connection Pool attributes is available in the [Apache Tomcat documentation](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html#Common_Attributes){target="\_blank"}, along with [guidance on tuning the pool for high-concurrency environments](https://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency){target="\_blank"}. --- -This work is a derivative of [How to Use an External Connection Pool](http://wiki.openbravo.com/wiki/How_to_Use_an_External_Connection_Pool){target="\_blank"} by [Openbravo Wiki](http://wiki.openbravo.com/wiki/Welcome_to_Openbravo){target="\_blank"}, used under [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="\_blank"}. This work is licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/){target="\_blank"} by [Etendo](https://etendo.software){target="\_blank"}. \ No newline at end of file +This work is a derivative of [How to Use an External Connection Pool](http://wiki.openbravo.com/wiki/How_to_Use_an_External_Connection_Pool){target="\_blank"} by [Openbravo Wiki](http://wiki.openbravo.com/wiki/Welcome_to_Openbravo){target="\_blank"}, used under [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="\_blank"}. This work is licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/){target="\_blank"} by [Etendo](https://etendo.software){target="\_blank"}. diff --git a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md new file mode 100644 index 0000000000..40d61b05d0 --- /dev/null +++ b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md @@ -0,0 +1,96 @@ +--- +title: Cómo diagnosticar conexiones en estado idle in transaction +tags: + - Pool de conexiones + - Solución de problemas + - Base de datos + - PostgreSQL + - Hibernate + - DAL +status: beta +--- + +# Cómo diagnosticar conexiones en estado idle in transaction { #how-to-diagnose-idle-in-transaction-connections } + +!!! example "IMPORTANTE: ESTA ES UNA VERSIÓN BETA" + Esta página está en desarrollo activo y puede contener **funcionalidades inestables o incompletas**. Úsela **bajo su propia responsabilidad**. + +## Visión general { #overview } + +Etendo atiende la mayoría de las solicitudes a través de `DalFilter`, que abre una sesión de Hibernate/DAL al inicio de la solicitud y la cierra una vez enviada la respuesta. Los servlets, procesos o endpoints de servicios web personalizados que llaman a `OBDal.getInstance()` o abren una sesión de `SessionHandler` fuera de ese ciclo de vida son responsables de cerrar la sesión ellos mismos. + +Una sesión que nunca se cierra mantiene su conexión JDBC subyacente retirada del pool con una transacción abierta. PostgreSQL informa esa conexión como `idle in transaction`. Si no se controla, esto bloquea el autovacuum en las tablas que tocó la transacción, provoca hinchazón de las tablas y degrada el rendimiento de la base de datos con el tiempo. Reiniciar Tomcat vacía el pool y oculta el síntoma temporalmente, por lo que la fuga subyacente puede pasar inadvertida durante un tiempo. + +## Detección del problema { #detecting-the-problem } + +Consulte PostgreSQL para buscar conexiones atascadas en este estado: + +```sql +SELECT pid, now() - query_start AS duration, state, LEFT(query, 80) AS query_snippet +FROM pg_stat_activity +WHERE state = 'idle in transaction'; +``` + +Un número creciente de filas que nunca se despeja hasta que se reinicia Tomcat indica que, en algún punto del recorrido de la solicitud, no se está cerrando una sesión. + +## Cómo encontrar la fuga { #finding-the-leak } + +Revise los caminos de código personalizados que abren una sesión DAL o de Hibernate directamente en lugar de depender de `DalFilter`. Esto es habitual en servlets que extienden directamente `HttpServlet` o `HttpBaseServlet`, evitando la cadena de filtros estándar. Cada uno de estos caminos debe cerrar su sesión explícitamente en un bloque `finally`: + +```java +try { + // ... procesamiento de la solicitud que usa OBDal.getInstance() ... +} finally { + OBDal.getInstance().commitAndClose(); +} +``` + +O, cuando se usa `SessionHandler` directamente: + +```java +try { + // ... procesamiento de la solicitud ... +} finally { + SessionHandler.getInstance().commitAndClose(); +} +``` + +Para confirmar qué camino de código es responsable antes de cambiar nada, habilite el registro de conexiones abandonadas. Esto registra la traza de pila de dónde se tomó prestada una conexión una vez que ha estado retirada más tiempo del esperado, sin cerrar nada: + +```properties title="gradle.properties" +db.pool.logAbandoned=true +db.pool.suspectTimeout= +``` + +Aplique el cambio con: + +```bash +./gradlew setup +``` + +!!! warning + Registrar las conexiones abandonadas añade sobrecarga a cada solicitud de conexión, porque se debe generar una traza de pila. Utilícelo para diagnosticar la fuga y luego deshabilítelo una vez identificado el camino de código responsable. + +## Mitigación a nivel de pool { #mitigating-at-the-pool-level } + +Mientras se desarrolla e implementa la corrección de código, el pool de conexiones puede configurarse para recuperar por la fuerza las conexiones que se han retirado durante demasiado tiempo. Añada las siguientes propiedades a `gradle.properties`: + +```properties title="gradle.properties" +db.pool.removeAbandoned=true +db.pool.removeAbandonedTimeout= +``` + +Luego aplique el cambio: + +```bash +./gradlew setup +``` + +Consulte [Cómo usar un pool de conexiones externo](how-to-use-an-external-connection-pool.md#pool-configuration) para ver la referencia completa de las propiedades de configuración del pool. + +!!! warning + Establezca `removeAbandonedTimeout` con un margen amplio por encima de la duración de la transacción o el proceso en segundo plano legítimo más largo del entorno. Cualquier operación que siga en ejecución más allá de ese tiempo de espera tendrá su conexión recuperada mientras está en uso, lo que corrompe esa operación. Este ajuste es una red de seguridad temporal, no un sustituto de cerrar la sesión en el código. + +--- + +This work is licensed under :material-creative-commons: :fontawesome-brands-creative-commons-by: :fontawesome-brands-creative-commons-sa: [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="_blank"} by [Futit Services S.L](https://etendo.software){target="_blank"}. diff --git a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 1156b95546..700431f6ec 100644 --- a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -17,25 +17,90 @@ status: beta ## Visión general { #overview } -De forma predeterminada, Etendo utiliza dos pools de conexiones: +Etendo incluye el [Apache JDBC Connection Pool](https://github.com/etendosoftware/etendo_core/tree/main/modules_core/org.openbravo.apachejdbcconnectionpool){target="\_blank"} habilitado de forma predeterminada, a través del módulo core `org.openbravo.apachejdbcconnectionpool`. Este módulo implementa la abstracción `ExternalConnectionPool` de Etendo sobre el [Apache Tomcat JDBC Connection Pool](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html){target="\_blank"}. No se requiere ningún paso de instalación: `Openbravo.properties` ya establece -- Pool de conexiones predeterminado de Hibernate para consultas relacionadas con DAL -- [Apache DBCP](https://commons.apache.org/proper/commons-dbcp/){target="\_blank"} para las conexiones proporcionadas por `ConnectionProviderImpl`. +```properties title="Openbravo.properties" +db.externalPoolClassName=org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool +``` -!!!info - Es posible especificar un proveedor de conexiones externo que Etendo utilizará para obtener las *conexiones JDBC*. Para ello, es necesario instalar un módulo que contenga una subclase de `ExternalConnectionPool`, y se debe establecer la propiedad `db.externalPoolClassName` en el archivo `gradle.properties`. +Dado que el pool ya está activo en toda instalación, el trabajo descrito en esta página consiste en ajustar sus propiedades — consulte [Configuración del pool](#pool-configuration) más abajo. Cambiar `db.externalPoolClassName` por otra clase solo es necesario para conectar una implementación de pool de conexiones externo **personalizada** en lugar de la incluida por defecto; consulte [Cómo crear un pool de conexiones externo](how-to-create-an-external-connection-pool.md) para ese escenario. + +Las propiedades del pool se establecen en `gradle.properties`. Después de añadir o modificar cualquiera de ellas, aplique el cambio con: -## Ejemplo: uso del pool de conexiones JDBC de Apache { #example-using-the-apache-jdbc-connection-pool } +```bash +./gradlew setup +``` -El módulo core [Apache JDBC Connection Pool](https://github.com/etendosoftware/etendo_core/tree/main/modules_core/org.openbravo.apachejdbcconnectionpool){target="\_blank"} proporciona una implementación del pool de conexiones JDBC de Apache. +Esto regenera `Openbravo.properties`, que es el archivo que `JdbcExternalConnectionPool` lee en tiempo de ejecución para construir el pool. -La propiedad `db.externalPoolClassName` debe establecerse en `gradle.properties`. Este módulo implementa la clase del pool de conexiones externo en la clase `org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool`, por lo que se debe añadir esta línea a `gralde.properties`: +## Configuración del pool { #pool-configuration } -``` title="Gradle.properties" -db.externalPoolClassName=org.openbravo.apachejdbcconnectionpool.JdbcExternalConnectionPool +Una instalación nueva de Etendo viene con las siguientes propiedades ya establecidas: + +```properties title="Openbravo.properties (generado)" +db.pool.initialSize=1 +db.pool.minIdle=5 +db.pool.maxActive=10000 +db.pool.timeBetweenEvictionRunsMillis=60000 +db.pool.minEvictableIdleTimeMillis=120000 +db.pool.removeAbandoned=false +db.pool.testOnBorrow=true +db.pool.testWhileIdle=false +db.pool.testOnReturn=false +db.pool.validationQuery=SELECT 1 FROM DUAL +db.pool.validationInterval=30000 +db.pool.jmxEnabled=false ``` -Este módulo contiene una plantilla de archivo de configuración: `modules_core/org.openbravo.apachejdbcconnectionpool/config/connectionPool.properties.template`. Para personalizar las propiedades del pool de conexiones JDBC, este archivo debe copiarse a `modules_core/org.openbravo.apachejdbcconnectionpool/config/connectionPool.properties`. El usuario puede entonces configurar las propiedades del pool según sus necesidades. Puede encontrar indicaciones sobre cómo configurar estas propiedades [aquí](https://tomcat.apache.org/){target="\_blank"}. +Puede sobrescribir cualquiera de ellas estableciendo la propiedad correspondiente en `gradle.properties`: + +| Propiedad | Descripción | Valor predeterminado | +| --- | --- | --- | +| `db.pool.initialSize` | Conexiones establecidas cuando arranca el pool. Se reduce automáticamente si supera `db.pool.maxActive`. | `1` | +| `db.pool.minIdle` | Número mínimo de conexiones establecidas que se mantienen en el pool en todo momento. El pool de conexiones inactivas no se reduce por debajo de este valor durante una ejecución de desalojo, pero puede bajar más si `db.pool.validationQuery` falla y se cierran conexiones. | `5` | +| `db.pool.maxActive` | Número máximo de conexiones activas que el pool puede entregar al mismo tiempo. Se mantiene alto de forma predeterminada porque la planificación de capacidad se delega a la base de datos; debería ser al menos tan alto como el número máximo de conexiones de la propia base de datos. Si se reduce por debajo de ese valor, `db.pool.maxWait` pasa a ser relevante. | `10000` | +| `db.pool.timeBetweenEvictionRunsMillis` | Cada cuánto (ms) el hilo sweeper revisa las conexiones inactivas y abandonadas. Consulte [¿Cómo funciona el hilo sweeper?](#how-does-the-sweeper-thread-work). No debería establecerse por debajo de `1000`. | `60000` | +| `db.pool.minEvictableIdleTimeMillis` | Tiempo mínimo (ms) que una conexión puede permanecer inactiva antes de que el sweeper la desaloje. | `120000` | +| `db.pool.removeAbandoned` | Si es `true`, las conexiones retenidas más tiempo que `db.pool.removeAbandonedTimeout` se recuperan por la fuerza. | `false` | +| `db.pool.testOnBorrow` | Valida una conexión antes de entregarla; si no es válida, la descarta y lo intenta de nuevo. Requiere que `db.pool.validationQuery` esté establecida. | `true` | +| `db.pool.testOnReturn` | Valida una conexión cuando se devuelve al pool. | `false` | +| `db.pool.testWhileIdle` | Valida periódicamente las conexiones inactivas. | `false` | +| `db.pool.validationQuery` | SQL utilizada para validar una conexión. No debe lanzar una excepción. Es obligatoria para que `testOnBorrow`, `testOnReturn` y `testWhileIdle` tengan algún efecto. | `SELECT 1 FROM DUAL` | +| `db.pool.validationInterval` | Milisegundos mínimos entre validaciones de la misma conexión, para evitar comprobaciones redundantes. | `30000` | +| `db.pool.jmxEnabled` | Expone las métricas del pool a través de JMX. | `false` | + +El pool también admite las siguientes propiedades. Etendo no establece un valor predeterminado para ninguna de ellas — cuando una propiedad no está establecida en `gradle.properties`, se aplica el valor predeterminado del [Apache Tomcat JDBC Connection Pool](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html#Common_Attributes){target="\_blank"} subyacente: + +| Propiedad | Descripción | +| --- | --- | +| `db.pool.maxIdle` | Número máximo de conexiones inactivas que se mantienen en el pool cuando el sweeper está deshabilitado. | +| `db.pool.maxWait` | Milisegundos que el pool espera a que se devuelva una conexión antes de lanzar una excepción, una vez alcanzado `db.pool.maxActive`. | +| `db.pool.numTestsPerEvictionRun` | Número de conexiones examinadas en cada ejecución del sweeper. | +| `db.pool.removeAbandonedTimeout` | Segundos que una conexión puede estar retirada antes de considerarse abandonada. Solo es relevante cuando `db.pool.removeAbandoned=true`. | +| `db.pool.testOnConnect` | Valida una conexión justo después de que se crea físicamente. | +| `db.pool.validatorClassName` | Clase validadora personalizada que se usa en lugar de `db.pool.validationQuery`. | +| `db.pool.initSQL` | SQL que se ejecuta una vez, justo después de crear una conexión física. | +| `db.pool.defaultAutoCommit` | Estado predeterminado de auto-commit de las conexiones que entrega el pool. | +| `db.pool.defaultReadOnly` | Estado de solo lectura predeterminado de las conexiones que entrega el pool. | +| `db.pool.defaultTransactionIsolation` | Nivel de aislamiento de transacción predeterminado de las conexiones que entrega el pool. | +| `db.pool.defaultCatalog` | Catálogo predeterminado de las conexiones que entrega el pool. | +| `db.pool.connectionProperties` | Propiedades de conexión adicionales específicas del driver, como una lista de pares `nombre=valor` separados por punto y coma. | +| `db.pool.accessToUnderlyingConnectionAllowed` | Permite obtener la conexión física subyacente a través del envoltorio de la conexión del pool. | +| `db.pool.logAbandoned` | Registra la traza de pila de dónde se tomó prestada una conexión una vez que ha estado retirada más tiempo que `db.pool.suspectTimeout`. Añade sobrecarga a cada solicitud de conexión, porque se debe generar una traza de pila. | +| `db.pool.suspectTimeout` | Segundos que una conexión puede estar retirada antes de registrarse como sospechosa. Solo es relevante cuando `db.pool.logAbandoned=true`. Es independiente de `db.pool.removeAbandoned` — una conexión sospechosa solo se registra, no se recupera. | +| `db.pool.name` | Nombre asignado al pool, útil para distinguir pools cuando hay varios configurados. | + +!!!info + Cualquiera de estas propiedades puede limitarse a un pool con nombre específico —por ejemplo, el pool de solo lectura— insertando el nombre del pool después de `db.`, por ejemplo `db.readonly.pool.maxActive`. Un valor específico de un pool tiene prioridad sobre el valor predeterminado `db.pool.*` para ese pool; un pool que no define su propio valor recurre al predeterminado. + +### ¿Cómo funciona el hilo sweeper? { #how-does-the-sweeper-thread-work } + +El sweeper es el hilo en segundo plano que se ejecuta cada `db.pool.timeBetweenEvictionRunsMillis` milisegundos para validar las conexiones inactivas y comprobar si hay conexiones abandonadas. Que esté habilitado o no cambia el comportamiento del pool de conexiones inactivas: + +- **Sweeper deshabilitado**: si el pool de conexiones inactivas crece por encima de `db.pool.maxIdle`, una conexión se cierra en cuanto se devuelve al pool en lugar de mantenerse inactiva. +- **Sweeper habilitado**: el número de conexiones inactivas puede crecer por encima de `db.pool.maxIdle`, pero vuelve a bajar hasta `db.pool.minIdle` una vez que una conexión ha estado inactiva más tiempo que `db.pool.minEvictableIdleTimeMillis`. + +La lista completa de atributos configurables del Tomcat JDBC Connection Pool está disponible en la [documentación de Apache Tomcat](https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html#Common_Attributes){target="\_blank"}, junto con [indicaciones para ajustar el pool en entornos de alta concurrencia](https://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency){target="\_blank"}. --- -Este trabajo es una obra derivada de [Cómo usar un pool de conexiones externo](http://wiki.openbravo.com/wiki/How_to_Use_an_External_Connection_Pool){target="\_blank"} de [Openbravo Wiki](http://wiki.openbravo.com/wiki/Welcome_to_Openbravo){target="\_blank"}, utilizada bajo [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="\_blank"}. Esta obra está licenciada bajo [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/){target="\_blank"} por [Etendo](https://etendo.software){target="\_blank"}. \ No newline at end of file +Este trabajo es una obra derivada de [Cómo usar un pool de conexiones externo](http://wiki.openbravo.com/wiki/How_to_Use_an_External_Connection_Pool){target="\_blank"} de [Openbravo Wiki](http://wiki.openbravo.com/wiki/Welcome_to_Openbravo){target="\_blank"}, utilizada bajo [CC BY-SA 2.5 ES](https://creativecommons.org/licenses/by-sa/2.5/es/){target="\_blank"}. Esta obra está licenciada bajo [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/){target="\_blank"} por [Etendo](https://etendo.software){target="\_blank"}. diff --git a/mkdocs.yml b/mkdocs.yml index 7ba01b2fd8..e6fcb68906 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -545,6 +545,7 @@ plugins: - How to Define Display Logic for Tabs: developer-guide/etendo-classic/how-to-guides/how-to-define-display-logic-for-tabs.md - How to Define the Timeout of a Query: developer-guide/etendo-classic/how-to-guides/how-to-define-the-timeout-of-a-query.md - How to Develop a DAL Background Process: developer-guide/etendo-classic/how-to-guides/how-to-develop-a-dal-background-process.md + - How to Diagnose Idle in Transaction Connections: developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md - How to do a Complex Query Using DAL: developer-guide/etendo-classic/how-to-guides/how-to-do-a-complex-query-using-the-dal.md - How to Document an Endpoint with OpenAPI: developer-guide/etendo-classic/how-to-guides/how-to-document-an-endpoint-with-openapi.md - How to Embed a Widget into a Window Tab: developer-guide/etendo-classic/how-to-guides/how-to-embed-a-widget-into-a-window-tab.md @@ -934,6 +935,7 @@ plugins: How to Define Display Logic for Tabs: Cómo Definir Lógica de Visualización para Pestañas How to Define the Timeout of a Query: Cómo Definir el Timeout de una Consulta How to Develop a DAL Background Process: Cómo Desarrollar un Proceso en Segundo Plano con DAL + How to Diagnose Idle in Transaction Connections: Cómo Diagnosticar Conexiones en Estado Idle in Transaction How to do a Complex Query Using DAL: Cómo Hacer una Consulta Compleja Usando DAL How to Document an Endpoint with OpenAPI: Cómo Documentar un Endpoint con OpenAPI How to Embed a Widget into a Window Tab: Cómo Insertar un Widget en una Pestaña de Ventana @@ -1587,6 +1589,7 @@ nav: - How to Define Display Logic for Tabs: developer-guide/etendo-classic/how-to-guides/how-to-define-display-logic-for-tabs.md - How to Define the Timeout of a Query: developer-guide/etendo-classic/how-to-guides/how-to-define-the-timeout-of-a-query.md - How to Develop a DAL Background Process: developer-guide/etendo-classic/how-to-guides/how-to-develop-a-dal-background-process.md + - How to Diagnose Idle in Transaction Connections: developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md - How to do a Complex Query Using DAL: developer-guide/etendo-classic/how-to-guides/how-to-do-a-complex-query-using-the-dal.md - How to Document an Endpoint with OpenAPI: developer-guide/etendo-classic/how-to-guides/how-to-document-an-endpoint-with-openapi.md - How to Embed a Widget into a Window Tab: developer-guide/etendo-classic/how-to-guides/how-to-embed-a-widget-into-a-window-tab.md From 8b5456009ff72947ffdd510b973cbaf32e12df72 Mon Sep 17 00:00:00 2001 From: Isaias Battaglia Date: Thu, 13 Aug 2026 14:51:18 -0300 Subject: [PATCH 2/3] Feature ETP-4296: Address Copilot review feedback Use xact_start instead of query_start in the idle-in-transaction detection query, since query_start reflects the last statement, not the open transaction's start. Clarify that the default db.pool.validationQuery value is Oracle syntax and document the PostgreSQL equivalent (SELECT 1). --- .../how-to-diagnose-idle-in-transaction-connections.md | 2 +- .../how-to-guides/how-to-use-an-external-connection-pool.md | 5 ++++- .../how-to-diagnose-idle-in-transaction-connections.md | 2 +- .../how-to-guides/how-to-use-an-external-connection-pool.md | 5 ++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md b/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md index 10e8238910..1a3bde9ee2 100644 --- a/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md +++ b/docs/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md @@ -26,7 +26,7 @@ A session that is never closed keeps its underlying JDBC connection checked out Query PostgreSQL for connections stuck in this state: ```sql -SELECT pid, now() - query_start AS duration, state, LEFT(query, 80) AS query_snippet +SELECT pid, now() - xact_start AS duration, state, LEFT(query, 80) AS query_snippet FROM pg_stat_activity WHERE state = 'idle in transaction'; ``` diff --git a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 6cae399518..0ca953dbc2 100644 --- a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -52,6 +52,9 @@ db.pool.validationInterval=30000 db.pool.jmxEnabled=false ``` +!!! info + The default `db.pool.validationQuery` value shown above is Oracle syntax. On a PostgreSQL installation, override it to `SELECT 1`, since PostgreSQL does not have a `DUAL` table. + Override any of them by setting the corresponding property in `gradle.properties`: | Property | Description | Default | @@ -65,7 +68,7 @@ Override any of them by setting the corresponding property in `gradle.properties | `db.pool.testOnBorrow` | Validates a connection before handing it out; drops and retries if invalid. Requires `db.pool.validationQuery` to be set. | `true` | | `db.pool.testOnReturn` | Validates a connection when it is returned to the pool. | `false` | | `db.pool.testWhileIdle` | Validates idle connections periodically. | `false` | -| `db.pool.validationQuery` | SQL used to validate a connection. Must not throw an exception. Required for `testOnBorrow`, `testOnReturn`, and `testWhileIdle` to have any effect. | `SELECT 1 FROM DUAL` | +| `db.pool.validationQuery` | SQL used to validate a connection. Must not throw an exception. Required for `testOnBorrow`, `testOnReturn`, and `testWhileIdle` to have any effect. | `SELECT 1 FROM DUAL` (Oracle) / `SELECT 1` (PostgreSQL) | | `db.pool.validationInterval` | Minimum milliseconds between validations of the same connection, to avoid redundant checks. | `30000` | | `db.pool.jmxEnabled` | Exposes pool metrics through JMX. | `false` | diff --git a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md index 40d61b05d0..d0e9d08191 100644 --- a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md +++ b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-diagnose-idle-in-transaction-connections.md @@ -26,7 +26,7 @@ Una sesión que nunca se cierra mantiene su conexión JDBC subyacente retirada d Consulte PostgreSQL para buscar conexiones atascadas en este estado: ```sql -SELECT pid, now() - query_start AS duration, state, LEFT(query, 80) AS query_snippet +SELECT pid, now() - xact_start AS duration, state, LEFT(query, 80) AS query_snippet FROM pg_stat_activity WHERE state = 'idle in transaction'; ``` diff --git a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 700431f6ec..38b50d8f49 100644 --- a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -52,6 +52,9 @@ db.pool.validationInterval=30000 db.pool.jmxEnabled=false ``` +!!! info + El valor predeterminado de `db.pool.validationQuery` que se muestra arriba es sintaxis de Oracle. En una instalación con PostgreSQL, sobrescríbalo a `SELECT 1`, ya que PostgreSQL no tiene una tabla `DUAL`. + Puede sobrescribir cualquiera de ellas estableciendo la propiedad correspondiente en `gradle.properties`: | Propiedad | Descripción | Valor predeterminado | @@ -65,7 +68,7 @@ Puede sobrescribir cualquiera de ellas estableciendo la propiedad correspondient | `db.pool.testOnBorrow` | Valida una conexión antes de entregarla; si no es válida, la descarta y lo intenta de nuevo. Requiere que `db.pool.validationQuery` esté establecida. | `true` | | `db.pool.testOnReturn` | Valida una conexión cuando se devuelve al pool. | `false` | | `db.pool.testWhileIdle` | Valida periódicamente las conexiones inactivas. | `false` | -| `db.pool.validationQuery` | SQL utilizada para validar una conexión. No debe lanzar una excepción. Es obligatoria para que `testOnBorrow`, `testOnReturn` y `testWhileIdle` tengan algún efecto. | `SELECT 1 FROM DUAL` | +| `db.pool.validationQuery` | SQL utilizada para validar una conexión. No debe lanzar una excepción. Es obligatoria para que `testOnBorrow`, `testOnReturn` y `testWhileIdle` tengan algún efecto. | `SELECT 1 FROM DUAL` (Oracle) / `SELECT 1` (PostgreSQL) | | `db.pool.validationInterval` | Milisegundos mínimos entre validaciones de la misma conexión, para evitar comprobaciones redundantes. | `30000` | | `db.pool.jmxEnabled` | Expone las métricas del pool a través de JMX. | `false` | From 44f16556b6486aaf1ce2c26342f9a079e3dbfad3 Mon Sep 17 00:00:00 2001 From: Isaias Battaglia Date: Thu, 13 Aug 2026 15:01:47 -0300 Subject: [PATCH 3/3] Feature ETP-4296: Correct validationQuery clarification Revert the previous claim that SELECT 1 FROM DUAL needs a PostgreSQL-specific override. Confirmed against a real PostgreSQL installation that Etendo's database creation scripts provision a DUAL compatibility table, so the default query runs unmodified on both PostgreSQL and Oracle. --- .../how-to-guides/how-to-use-an-external-connection-pool.md | 5 +---- .../how-to-guides/how-to-use-an-external-connection-pool.md | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 0ca953dbc2..121201d850 100644 --- a/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -52,9 +52,6 @@ db.pool.validationInterval=30000 db.pool.jmxEnabled=false ``` -!!! info - The default `db.pool.validationQuery` value shown above is Oracle syntax. On a PostgreSQL installation, override it to `SELECT 1`, since PostgreSQL does not have a `DUAL` table. - Override any of them by setting the corresponding property in `gradle.properties`: | Property | Description | Default | @@ -68,7 +65,7 @@ Override any of them by setting the corresponding property in `gradle.properties | `db.pool.testOnBorrow` | Validates a connection before handing it out; drops and retries if invalid. Requires `db.pool.validationQuery` to be set. | `true` | | `db.pool.testOnReturn` | Validates a connection when it is returned to the pool. | `false` | | `db.pool.testWhileIdle` | Validates idle connections periodically. | `false` | -| `db.pool.validationQuery` | SQL used to validate a connection. Must not throw an exception. Required for `testOnBorrow`, `testOnReturn`, and `testWhileIdle` to have any effect. | `SELECT 1 FROM DUAL` (Oracle) / `SELECT 1` (PostgreSQL) | +| `db.pool.validationQuery` | SQL used to validate a connection. Must not throw an exception. Required for `testOnBorrow`, `testOnReturn`, and `testWhileIdle` to have any effect. Etendo's database creation scripts provision a `DUAL` compatibility table on PostgreSQL installations, so this query runs unmodified on both PostgreSQL and Oracle. | `SELECT 1 FROM DUAL` | | `db.pool.validationInterval` | Minimum milliseconds between validations of the same connection, to avoid redundant checks. | `30000` | | `db.pool.jmxEnabled` | Exposes pool metrics through JMX. | `false` | diff --git a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md index 38b50d8f49..3bc5cfcae9 100644 --- a/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md +++ b/docs/es/developer-guide/etendo-classic/how-to-guides/how-to-use-an-external-connection-pool.md @@ -52,9 +52,6 @@ db.pool.validationInterval=30000 db.pool.jmxEnabled=false ``` -!!! info - El valor predeterminado de `db.pool.validationQuery` que se muestra arriba es sintaxis de Oracle. En una instalación con PostgreSQL, sobrescríbalo a `SELECT 1`, ya que PostgreSQL no tiene una tabla `DUAL`. - Puede sobrescribir cualquiera de ellas estableciendo la propiedad correspondiente en `gradle.properties`: | Propiedad | Descripción | Valor predeterminado | @@ -68,7 +65,7 @@ Puede sobrescribir cualquiera de ellas estableciendo la propiedad correspondient | `db.pool.testOnBorrow` | Valida una conexión antes de entregarla; si no es válida, la descarta y lo intenta de nuevo. Requiere que `db.pool.validationQuery` esté establecida. | `true` | | `db.pool.testOnReturn` | Valida una conexión cuando se devuelve al pool. | `false` | | `db.pool.testWhileIdle` | Valida periódicamente las conexiones inactivas. | `false` | -| `db.pool.validationQuery` | SQL utilizada para validar una conexión. No debe lanzar una excepción. Es obligatoria para que `testOnBorrow`, `testOnReturn` y `testWhileIdle` tengan algún efecto. | `SELECT 1 FROM DUAL` (Oracle) / `SELECT 1` (PostgreSQL) | +| `db.pool.validationQuery` | SQL utilizada para validar una conexión. No debe lanzar una excepción. Es obligatoria para que `testOnBorrow`, `testOnReturn` y `testWhileIdle` tengan algún efecto. Los scripts de creación de base de datos de Etendo aprovisionan una tabla de compatibilidad `DUAL` en instalaciones PostgreSQL, por lo que esta consulta se ejecuta sin modificaciones tanto en PostgreSQL como en Oracle. | `SELECT 1 FROM DUAL` | | `db.pool.validationInterval` | Milisegundos mínimos entre validaciones de la misma conexión, para evitar comprobaciones redundantes. | `30000` | | `db.pool.jmxEnabled` | Expone las métricas del pool a través de JMX. | `false` |