diff --git a/ems-core/src/main/java/it/integry/ems/datasource/DataSource.java b/ems-core/src/main/java/it/integry/ems/datasource/DataSource.java index 2c4271580f..349c585523 100644 --- a/ems-core/src/main/java/it/integry/ems/datasource/DataSource.java +++ b/ems-core/src/main/java/it/integry/ems/datasource/DataSource.java @@ -1,175 +1,173 @@ -package it.integry.ems.datasource; - -import it.integry.ems.settings.Model.AvailableConnectionsModel; -import it.integry.ems.settings.Model.SettingsModel; -import it.integry.ems.sync.MultiDBTransaction.Connection; -import it.integry.ems.utility.UtilityDebug; -import it.integry.ems_model.config.EmsRestConstants; -import it.integry.ems_model.utility.UtilityDB; -import it.integry.ems_model.utility.UtilityHashMap; -import it.integry.ems_model.utility.UtilityString; -import org.apache.commons.dbcp2.BasicDataSource; - -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; - -public class DataSource extends BasicDataSource { - - private AvailableConnectionsModel connectionModel; - - /** - * Instanzia un nuovo datasource. - * - * @deprecated Il datasource non deve essere istanziato direttamente ma bisogna utilizzare il metodo - * {@link it.integry.ems.sync.MultiDBTransaction.BasicConnectionPool#getConnection(AvailableConnectionsModel)} per ottenere una connessione. - */ - @Deprecated - public DataSource() { - super(); - } - - public EmsRestConstants.DB_TYPE getTypeDB() { - return connectionModel.getConnectionType(); - } - - /** - * Ottiene una connessione dal pool. La connessione è wrappata in it.integry.ems.sync.MultiDBTransaction.Connection. - * È responsabilità del chiamante chiudere la connessione per restituirla al pool. - * - * @return una connessione dal pool - * @throws SQLException se si verifica un errore di accesso al database - */ - - public Connection getConnection() throws SQLException { - // Restituisce una nuova connessione dal pool di BasicDataSource, wrappata nel nostro tipo Connection - final Connection connection = Connection.fromConnection(super.getConnection()); - // Prova a ottenere una connessione per verificare la configurazione e ottenere il sessionID - - if (connectionModel.getConnectionType() == EmsRestConstants.DB_TYPE.MSSQL) { - HashMap resultSessionData = UtilityDB.executeSimpleQueryOnlyFirstRow(connection, "select CAST(@@spid AS BIGINT) AS session_id," + - " user_name() AS [user_name]," + - " suser_name() AS [suser_name]," + - " current_user AS [current_user]," + - " system_user AS [system_user]," + - " session_user AS [session_user]," + - " user AS [user]"); - - connection.setSessionId(UtilityHashMap.getValueIfExists(resultSessionData, "session_id")); - } - - connection.setProfileName(connectionModel.getProfileName()) - .setInternalDb(connectionModel.getInternalDb()); - - return connection; - } - - public synchronized void initialize(AvailableConnectionsModel connectionModel) throws Exception { - this.connectionModel = connectionModel; - - this.setDriverClassName(connectionModel.getDriverClassName()); - - this.setUrl(connectionModel.getDbConnectionString("EMS Connection")); - this.setUsername(connectionModel.getUsername()); - this.setPassword(connectionModel.getPasswordDecrypted()); - - this.setDefaultTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED); - this.setDefaultAutoCommit(false); - - // ===== OTTIMIZZAZIONI CRITICHE ===== - - // Pool sizing ottimizzato per READ_UNCOMMITTED (meno locking = più connessioni possibili) - this.setInitialSize(5); // Inizia con più connessioni -// this.setMaxTotal(20); // Aumentato il massimo - this.setMaxIdle(15); // Mantieni più connessioni idle - this.setMinIdle(5); // Non scendere sotto 5 - - // Timeout ottimizzati per performance massime - this.setMaxWaitMillis(2000); // Ridotto a 2 secondi - - // Validazione veloce ed efficiente - this.setValidationQuery("SELECT 1"); - this.setValidationQueryTimeout(60); // Ridotto a 1 secondo - this.setTestOnBorrow(true); // Testa quando prendi la connessione - this.setTestOnReturn(false); // Non testare quando restituisci (performance) - this.setTestWhileIdle(true); // Testa connessioni idle - - // Eviction ottimizzata per READ_UNCOMMITTED - this.setTimeBetweenEvictionRunsMillis(30000); // Ogni 30 secondi - this.setMinEvictableIdleTimeMillis(180000); // 3 minuti (ridotto da 5) - this.setNumTestsPerEvictionRun(5); // Testa più connessioni per volta - - // Connection leak protection - this.setRemoveAbandonedOnBorrow(true); - this.setRemoveAbandonedOnMaintenance(true); - this.setRemoveAbandonedTimeout(60 * 10); // 60 secondi - this.setLogAbandoned(UtilityDebug.isDebugExecution()); // Disabilita in produzione per performance - - // Performance boosts massimi - this.setPoolPreparedStatements(true); - this.setMaxOpenPreparedStatements(200); - this.setCacheState(true); - this.setFastFailValidation(true); - - // Ottimizzazioni specifiche per SQL Server con READ_UNCOMMITTED - if (connectionModel.getConnectionType() == EmsRestConstants.DB_TYPE.MSSQL) { - // Impostazioni connection specifiche per SQL Server - //this.setConnectionInitSqls(java.util.Arrays.asList( - //"SET NOCOUNT ON", - //"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", - //"SET ARITHABORT ON" - //)); - } - - // Logging ottimizzato (disabilita in produzione) - this.setLogExpiredConnections(UtilityDebug.isDebugExecution()); - this.setAccessToUnderlyingConnectionAllowed(true); // Per performance avanzate - - // ==================== ULTERIORI OTTIMIZZAZIONI ==================== - - // Connection properties specifiche per performance - this.setDefaultReadOnly(false); - this.setDefaultCatalog(null); // Lascia che sia il driver a gestire - - // Ottimizzazioni DBCP2 avanzate - this.setLifo(false); // FIFO per distribuzione equa delle connessioni - this.setSoftMinEvictableIdleTimeMillis(120000); // 2 minuti soft eviction - - - if (!connectionModel.getInternalDb() || - UtilityDebug.isDebugExecution() || - UtilityDebug.isIntegryServerDev() || - !SettingsModel.getInstance().isPrimaryInstance()) { - this.setInitialSize(0); -// this.setMaxTotal(5); - this.setMinIdle(0); - this.setMaxIdle(1); - } - } - - public synchronized void initialize(String profileDB, String connectionName) throws Exception { - if (UtilityString.isNullOrEmpty(profileDB)) { - throw new Exception("Profile DB non valorizzato - controllare la chiamata del servizio"); - } - - AvailableConnectionsModel connectionModel = null; - List availableConnectionsModels = SettingsModel.getInstance().getAvailableConnectionsWithoutDuplicatedProfiles(false); - - for (AvailableConnectionsModel connectionsModel : availableConnectionsModels) { - if (connectionsModel.getProfileName().equalsIgnoreCase(profileDB)) { - connectionModel = connectionsModel; - } - } - - if (connectionModel == null) { - throw new Exception(String.format("Configurazione DB non trovata o dati mancanti (%s)", profileDB)); - } - - initialize(connectionModel); - } - - public synchronized void initialize(String profileDB) throws Exception { - initialize(profileDB, "EMS Connection"); - } - +package it.integry.ems.datasource; + +import it.integry.ems.settings.Model.AvailableConnectionsModel; +import it.integry.ems.settings.Model.SettingsModel; +import it.integry.ems.sync.MultiDBTransaction.Connection; +import it.integry.ems.utility.UtilityDebug; +import it.integry.ems_model.config.EmsRestConstants; +import it.integry.ems_model.utility.UtilityDB; +import it.integry.ems_model.utility.UtilityHashMap; +import it.integry.ems_model.utility.UtilityString; +import org.apache.commons.dbcp2.BasicDataSource; + +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; + +public class DataSource extends BasicDataSource { + + private AvailableConnectionsModel connectionModel; + + /** + * Instanzia un nuovo datasource. + * + * @deprecated Il datasource non deve essere istanziato direttamente ma bisogna utilizzare il metodo + * {@link it.integry.ems.sync.MultiDBTransaction.BasicConnectionPool#getConnection(AvailableConnectionsModel)} per ottenere una connessione. + */ + @Deprecated + public DataSource() { + super(); + } + + public EmsRestConstants.DB_TYPE getTypeDB() { + return connectionModel.getConnectionType(); + } + + /** + * Ottiene una connessione dal pool. La connessione è wrappata in it.integry.ems.sync.MultiDBTransaction.Connection. + * È responsabilità del chiamante chiudere la connessione per restituirla al pool. + * + * @return una connessione dal pool + * @throws SQLException se si verifica un errore di accesso al database + */ + + public Connection getConnection() throws SQLException { + // Restituisce una nuova connessione dal pool di BasicDataSource, wrappata nel nostro tipo Connection + final Connection connection = Connection.fromConnection(super.getConnection()); + // Prova a ottenere una connessione per verificare la configurazione e ottenere il sessionID + + if (connectionModel.getConnectionType() == EmsRestConstants.DB_TYPE.MSSQL) { + HashMap resultSessionData = UtilityDB.executeSimpleQueryOnlyFirstRow(connection, "select CAST(@@spid AS BIGINT) AS session_id," + + " user_name() AS [user_name]," + + " suser_name() AS [suser_name]," + + " current_user AS [current_user]," + + " system_user AS [system_user]," + + " session_user AS [session_user]," + + " user AS [user]"); + + connection.setSessionId(UtilityHashMap.getValueIfExists(resultSessionData, "session_id")); + } + + connection.setProfileName(connectionModel.getProfileName()) + .setInternalDb(connectionModel.getInternalDb()); + + return connection; + } + + public synchronized void initialize(AvailableConnectionsModel connectionModel) throws Exception { + this.connectionModel = connectionModel; + + this.setDriverClassName(connectionModel.getDriverClassName()); + + this.setUrl(connectionModel.getDbConnectionString("EMS Connection")); + this.setUsername(connectionModel.getUsername()); + this.setPassword(connectionModel.getPasswordDecrypted()); + + this.setDefaultTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED); + this.setDefaultAutoCommit(false); + + // ===== OTTIMIZZAZIONI CRITICHE ===== + + // Pool sizing ottimizzato per READ_UNCOMMITTED (meno locking = più connessioni possibili) + this.setInitialSize(5); // Inizia con più connessioni +// this.setMaxTotal(20); // Aumentato il massimo + this.setMaxIdle(15); // Mantieni più connessioni idle + this.setMinIdle(5); // Non scendere sotto 5 + + // Timeout ottimizzati per performance massime + // this.setMaxWaitMillis(-1L); // Infinito (DEFAULT) + + // Validazione veloce ed efficiente + this.setValidationQuery("SELECT 1"); + this.setValidationQueryTimeout(5); // Ridotto a 1 secondo + this.setTestWhileIdle(true); // Testa connessioni idle + + // Eviction ottimizzata per READ_UNCOMMITTED + // this.setTimeBetweenEvictionRunsMillis(1 * 1000); // Ogni 30 secondi + // this.setMinEvictableIdleTimeMillis(3 * 60 * 1000); // 3 minuti (ridotto da 5) + // this.setNumTestsPerEvictionRun(5); // Testa più connessioni per volta + + // Connection leak protection + // this.setRemoveAbandonedOnBorrow(true); + // this.setRemoveAbandonedOnMaintenance(true); + // this.setRemoveAbandonedTimeout(60 * 10); // 60 secondi + this.setLogAbandoned(UtilityDebug.isDebugExecution()); // Disabilita in produzione per performance + + // Performance boosts massimi + this.setPoolPreparedStatements(true); +// this.setMaxOpenPreparedStatements(200); + // this.setCacheState(true); + this.setFastFailValidation(true); + + // Ottimizzazioni specifiche per SQL Server con READ_UNCOMMITTED + if (connectionModel.getConnectionType() == EmsRestConstants.DB_TYPE.MSSQL) { + // Impostazioni connection specifiche per SQL Server + //this.setConnectionInitSqls(java.util.Arrays.asList( + //"SET NOCOUNT ON", + //"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", + //"SET ARITHABORT ON" + //)); + } + + // Logging ottimizzato (disabilita in produzione) + this.setLogExpiredConnections(UtilityDebug.isDebugExecution()); + this.setAccessToUnderlyingConnectionAllowed(true); // Per performance avanzate + + // ==================== ULTERIORI OTTIMIZZAZIONI ==================== + + // Connection properties specifiche per performance + this.setDefaultReadOnly(false); + this.setDefaultCatalog(null); // Lascia che sia il driver a gestire + + // Ottimizzazioni DBCP2 avanzate + this.setLifo(false); // FIFO per distribuzione equa delle connessioni + this.setSoftMinEvictableIdleTimeMillis(120000); // 2 minuti soft eviction + + + if (!connectionModel.getInternalDb() || + UtilityDebug.isDebugExecution() || + UtilityDebug.isIntegryServerDev() || + !SettingsModel.getInstance().isPrimaryInstance()) { + this.setInitialSize(0); +// this.setMaxTotal(5); + this.setMinIdle(0); + this.setMaxIdle(1); + } + } + + public synchronized void initialize(String profileDB, String connectionName) throws Exception { + if (UtilityString.isNullOrEmpty(profileDB)) { + throw new Exception("Profile DB non valorizzato - controllare la chiamata del servizio"); + } + + AvailableConnectionsModel connectionModel = null; + List availableConnectionsModels = SettingsModel.getInstance().getAvailableConnectionsWithoutDuplicatedProfiles(false); + + for (AvailableConnectionsModel connectionsModel : availableConnectionsModels) { + if (connectionsModel.getProfileName().equalsIgnoreCase(profileDB)) { + connectionModel = connectionsModel; + } + } + + if (connectionModel == null) { + throw new Exception(String.format("Configurazione DB non trovata o dati mancanti (%s)", profileDB)); + } + + initialize(connectionModel); + } + + public synchronized void initialize(String profileDB) throws Exception { + initialize(profileDB, "EMS Connection"); + } + } \ No newline at end of file