mirror of
https://github.com/KeymonSoft/jRDC-MultiDB-Hikari.git
synced 2026-04-17 21:06:23 +00:00
253 lines
9.7 KiB
QBasic
253 lines
9.7 KiB
QBasic
B4J=true
|
|
Group=Default Group
|
|
ModulesStructureVersion=1
|
|
Type=Class
|
|
Version=4.19
|
|
@EndOfDesignText@
|
|
' Módulo de clase: RDCConnector
|
|
' Esta clase gestiona el pool de conexiones a una base de datos específica.
|
|
' REFRACTORIZADO: Usa ConnectionPoolManager y delega a HikariCP.
|
|
|
|
Sub Class_Globals
|
|
' --- Variables globales de la clase ---
|
|
Private pool As ConnectionPoolManager ' Usa el Manager para la modularidad
|
|
Private MyHikariPool As HikariConnectionPool ' <-- NUEVO: Pool dedicado a esta DBKey.
|
|
Private DebugQueries As Boolean = False ' Bandera para activar/desactivar el modo de depuración
|
|
Public commands As Map ' Comandos SQL cargados
|
|
Public serverPort As Int
|
|
Public usePool As Boolean = True
|
|
Public config As Map ' Configuración completa (JdbcUrl, User, Password, etc.)
|
|
Public IsParameterToleranceEnabled As Boolean ' Tolerancia a parámetros de más
|
|
Dim driverProperties As Map ' CRÍTICO: Propiedades específicas del driver (MySQL statement caching)
|
|
Private configLocation As String ' Ubicación del archivo de configuración
|
|
Private poolProperties As Map
|
|
End Sub
|
|
|
|
' Subrutina de inicialización para el conector de una base de datos específica.
|
|
Public Sub Initialize(DB As String)
|
|
' Nota: Este código asume que MyHikariPool ya está declarado en Class_Globals
|
|
Dim dbKey As String = DB ' Usaremos DB como la llave
|
|
If DB.EqualsIgnoreCase("DB1") Then dbKey = ""
|
|
|
|
poolProperties.Initialize
|
|
driverProperties.Initialize
|
|
|
|
' PASO 1: Cargar la configuración desde el archivo .properties correspondiente.
|
|
config = LoadConfigMap(dbKey) ' Aseguramos la carga en la variable de clase [1]
|
|
|
|
' Lectura de la configuración de tolerancia de parámetros
|
|
Dim toleranceSetting As Int = config.GetDefault("parameterTolerance", 0).As(Int)
|
|
IsParameterToleranceEnabled = (toleranceSetting = 1)
|
|
|
|
If IsParameterToleranceEnabled Then
|
|
Log($"RDCConnector.Initialize para ${dbKey}: Tolerancia a parámetros extras, HABILITADA."$)
|
|
Else
|
|
Log($"RDCConnector.Initialize para ${dbKey}: Tolerancia a parámetros extras, DESHABILITADA (modo estricto)."$)
|
|
End If
|
|
|
|
' Bloque Try-Catch para la inicialización y configuración del pool.
|
|
Try
|
|
Dim driverClass As String = config.Get("DriverClass")
|
|
Dim jdbcUrl As String = config.Get("JdbcUrl")
|
|
Dim aUser As String = config.Get("User")
|
|
Dim aPassword As String = config.Get("Password")
|
|
Dim poolType As String = "Hikari" ' Forzamos Hikari
|
|
|
|
' *** INICIO DE LA LÓGICA DE PRECEDENCIA DE TAMAÑO (HIKARI) ***
|
|
Dim maxSizeKey As String = $"pool.${poolType.ToLowerCase}.maximumpoolsize"$
|
|
Dim poolSizeString As String
|
|
Dim poolSize As Int
|
|
|
|
' Intentamos leer el valor específico (pool.hikari.maximumpoolsize).
|
|
If config.ContainsKey(maxSizeKey) Then
|
|
poolSizeString = config.Get(maxSizeKey)
|
|
poolSize = poolSizeString.As(Int)
|
|
Else
|
|
' Si no está definido, usamos el default recomendado por Hikari (10). [2]
|
|
poolSize = 10
|
|
End If
|
|
|
|
If poolSize < 1 Then poolSize = 10 ' Mantenemos la sensatez
|
|
Log($"RDCConnector: Usando MaximumPoolSize para ${poolType} calculado: ${poolSize}"$)
|
|
|
|
' *** PASO 2: INICIALIZA/CREA EL POOL LOCALMENTE (Decoupling CRÍTICO) ***
|
|
|
|
If MyHikariPool.IsInitialized = False Then MyHikariPool.Initialize ' Inicializa el wrapper local
|
|
|
|
' Crea el pool subyacente (DataSource) en esta instancia dedicada. [3]
|
|
MyHikariPool.CreatePool2(driverClass, jdbcUrl, aUser, aPassword, poolSize)
|
|
|
|
' PASO 3a: Cargar y filtrar SOLO las propiedades del Pool (ej. las que comienzan con 'pool.hikari.')
|
|
LoadPoolProperties(poolType, config)
|
|
|
|
' PASO 3b: Aplicar propiedades de ESTABILIDAD (Pool Properties)
|
|
If poolProperties.Size > 0 Then
|
|
' Aplicación directa al pool local. [4]
|
|
CallSub2(MyHikariPool, "SetProperties", poolProperties)
|
|
End If
|
|
|
|
' PASO 4: Cargar propiedades específicas del Driver (ej. Statement Caching)
|
|
If config.ContainsKey("DriverShortName") Then
|
|
LoadDriverProperties(config.Get("DriverShortName"), config)
|
|
End If
|
|
|
|
' PASO 5: Aplicar propiedades de RENDIMIENTO (Driver Properties)
|
|
If driverProperties.Size > 0 Then
|
|
' Aplicación directa al pool local. [5]
|
|
CallSub2(MyHikariPool, "SetDriverProperties", driverProperties)
|
|
Log($"RDCConnector.Initialize para ${DB}: {driverProperties.Size} propiedades del Driver aplicadas a HikariCP."$)
|
|
End If
|
|
|
|
' PASO 6 (Prueba de vida): Forzar la creación de conexiones iniciales y verificar el estado.
|
|
' Esto garantiza el fail-fast. [6]
|
|
Dim tempCon As SQL = MyHikariPool.GetConnection
|
|
If tempCon.IsInitialized Then
|
|
tempCon.Close
|
|
End If
|
|
|
|
' Cargar configuración estática en el cache global
|
|
Dim dbKeyToStore As String = DB
|
|
If dbKeyToStore = "" Then dbKeyToStore = "DB1"
|
|
|
|
' Almacenamos el mapa completo (configuración estática + métricas dinámicas iniciales) en el cache global.
|
|
' GetPoolStats ahora usa MyHikariPool.
|
|
Dim initialPoolStats As Map = GetPoolStats
|
|
Main.LatestPoolStats.Put(dbKeyToStore, initialPoolStats)
|
|
|
|
Catch
|
|
' Si ocurre un error durante la inicialización del pool o al forzar la conexión.
|
|
Dim ErrorMsg As String = $"RDCConnector.Initialize para ${DB}: ERROR CRÍTICO al inicializar/forzar conexión: ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
Main.LogServerError("ERROR", "RDCConnector.Initialize", ErrorMsg, DB, Null, Null)
|
|
|
|
' Si falla la inicialización, la instancia local MyHikariPool se queda inutilizada.
|
|
' Aquí podríamos considerar la opción de llamar a MyHikariPool.ClosePool para asegurar
|
|
' que no queden recursos parciales, aunque HikariCP debería manejarse con fail-fast.
|
|
|
|
End Try
|
|
|
|
' Carga los comandos SQL predefinidos de esta base de datos en el mapa global 'commandsMap' de Main.
|
|
If dbKey = "" Then dbKey = "DB1"
|
|
LoadSQLCommands(config, dbKey)
|
|
serverPort = config.Get("ServerPort")
|
|
|
|
End Sub
|
|
|
|
' Carga el mapa de configuración
|
|
Private Sub LoadConfigMap(DB As String) As Map
|
|
Private DBX As String = ""
|
|
If DB <> "" Then DBX = "." & DB
|
|
Log($"RDCConnector.LoadConfigMap: Leemos el config${DBX}.properties"$)
|
|
Return File.ReadMap("./", "config" & DBX & ".properties")
|
|
End Sub
|
|
|
|
' Obtiene la sentencia SQL completa para un comando dado.
|
|
Public Sub GetCommand(DB As String, Key As String) As String
|
|
commands = Main.commandsMap.Get(DB).As(Map)
|
|
If commands.ContainsKey("sql." & Key) = False Then
|
|
Dim ErrorMsg As String = $"RDCConnector.GetCommand: *** Comando no encontrado: '${Key}' para DB: '${DB}' ***"$
|
|
Log(ErrorMsg)
|
|
Main.LogServerError("ERROR", "RDCConnector.GetCommand", ErrorMsg, DB, Key, Null)
|
|
End If
|
|
Return commands.Get("sql." & Key)
|
|
End Sub
|
|
|
|
' Obtiene una conexión SQL funcional del pool de conexiones.
|
|
Public Sub GetConnection(DB As String) As SQL
|
|
' If DB.EqualsIgnoreCase("DB1") Then DB = ""
|
|
' If DebugQueries Then LoadSQLCommands(LoadConfigMap(DB), DB) ' Deshabilitado por defecto. [13]
|
|
|
|
' Devolvemos la conexión del pool local, si está inicializado.
|
|
If MyHikariPool.IsInitialized Then
|
|
Return MyHikariPool.GetConnection
|
|
Else
|
|
Log($"ERROR: Intento de obtener conexión de DBKey ${DB}, pero MyHikariPool no está inicializado."$)
|
|
' Devolver Null o lanzar excepción, dependiendo del manejo de errores deseado.
|
|
Return Null
|
|
End If
|
|
' ANTES: Return Main.ConnectionPoolManager1.GetConnection
|
|
End Sub
|
|
|
|
' Carga todos los comandos SQL del mapa de configuración en el mapa global 'commandsMap' de Main.
|
|
Private Sub LoadSQLCommands(config2 As Map, DB As String)
|
|
Dim newCommands As Map
|
|
newCommands.Initialize
|
|
For Each k As String In config2.Keys
|
|
If k.StartsWith("sql.") Then
|
|
newCommands.Put(k, config2.Get(k))
|
|
End If
|
|
Next
|
|
commands = newCommands
|
|
Main.commandsMap.Put(DB, commands)
|
|
End Sub
|
|
|
|
' ** Delegación de estadísticas de C3P0 a HikariCP **
|
|
Public Sub GetPoolStats As Map
|
|
Dim stats As Map
|
|
stats.Initialize
|
|
|
|
If MyHikariPool.IsInitialized Then
|
|
Try
|
|
' 2. Llamamos al método delegado GetStats en el wrapper de HikariCP.
|
|
Dim hikariStats As Map = MyHikariPool.GetStats
|
|
Return hikariStats
|
|
Catch
|
|
' Fallo en el método GetStats del wrapper.
|
|
Dim ErrorMsg As String = $"RDCConnector.GetPoolStats: ERROR CRÍTICO al obtener estadísticas de HikariCP: ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
stats.Put("Error", LastException.Message)
|
|
End Try
|
|
Else
|
|
stats.Put("Error", "Pool local MyHikariPool no inicializado.")
|
|
End If
|
|
|
|
Return stats
|
|
End Sub
|
|
|
|
' *** NUEVA SUBRUTINA: Cierra el pool de conexiones de forma ordenada ***
|
|
Public Sub Close
|
|
If MyHikariPool.IsInitialized Then
|
|
' Cierre limpio del pool subyacente.
|
|
MyHikariPool.ClosePool
|
|
Log($"RDCConnector.Close: Pool Hikari cerrado limpiamente para este conector."$)
|
|
End If
|
|
' Ya NO delegamos el cierre al Manager.
|
|
' ANTES: Main.ConnectionPoolManager1.ClosePoolByType(poolType) [15]
|
|
End Sub
|
|
|
|
' --- SUBRUTINAS DE UTILIDAD PARA CARGA DE PROPIEDADES ---
|
|
|
|
' [2]
|
|
Private Sub LoadDriverProperties(driverShortName As String, config_ As Map)
|
|
driverProperties = ExtractProperties($"driver.${driverShortName.trim}."$, config_, Null, Null)
|
|
End Sub
|
|
|
|
' [3]
|
|
Private Sub ExtractProperties(prefix As String, input As Map, newPrefix As String, output As Map) As Map
|
|
Dim properties As Map
|
|
If output = Null Or output.IsInitialized = False Then
|
|
properties.Initialize
|
|
Else
|
|
properties = output
|
|
End If
|
|
If newPrefix.EqualsIgnoreCase(Null) Then newPrefix = ""
|
|
Dim prefixLength As Int = prefix.Length
|
|
|
|
' Log($"Prefijo=${prefix}, ${newPrefix}"$)
|
|
For Each k As String In input.Keys
|
|
' Log(k)
|
|
If k.ToLowerCase.StartsWith(prefix) Then
|
|
' Log($"found ${prefix}"$)
|
|
Dim standardizedKey As String = k.SubString(prefixLength).ToLowerCase
|
|
' Log("Ponemos: " & $"${newPrefix}${k.SubString(prefixLength)}, ${input.Get(k)}"$)
|
|
properties.Put($"${newPrefix}${standardizedKey}"$, input.Get(k))
|
|
End If
|
|
Next
|
|
|
|
Return properties
|
|
End Sub
|
|
|
|
Private Sub LoadPoolProperties(poolType As String, config_ As Map)
|
|
' Busca entradas como 'pool.hikari.<propiedad>' y las extrae.
|
|
poolProperties = ExtractProperties($"pool.${poolType.ToLowerCase}."$, config_, Null, Null)
|
|
End Sub |