Merge remote-tracking branch 'origin/develop' into develop
All checks were successful
IntegryManagementSystem_Multi/pipeline/head This commit looks good

This commit is contained in:
2025-09-03 12:36:28 +02:00

View File

@@ -1,175 +1,175 @@
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<String, Object> 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<AvailableConnectionsModel> 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<String, Object> 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<AvailableConnectionsModel> 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");
}
}