B4J Question JBDC pool connections: how to use correctly ?

peacemaker

Expert
Licensed User
Longtime User
HI, All

If a B4J server app (works on a Host1 of a LAN) uses a big MySQL database on a dedicated Host0 (of this LAN), and also planned to make other apps on different hostsX (and connecting to the same Host0 db) - how correctly to use the connections pool to avoid errors ?

There are tons of subs inside the app where the DB is used - is a new connection to be opened at each sub and closed at sub finish ?
 

peacemaker

Expert
Licensed User
Longtime User
No, with just iteration along the ResultSet with commented all inside - the same error after some loops:

B4X:
init mysql
2023-10-12 20:18:39.209:INFO :cmvci.AbstractPoolBackedDataSource:pool-1-thread-3: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 20000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge15jaza6effljjbobg|6b1c0b35, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge15jaza6effljjbobg|6b1c0b35, idleConnectionTestPeriod -> 600, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost/stancontrol?characterEncoding=utf8&allowPublicKeyRetrieval=false&au
toReconnect=false&requireSSL=false&useSSL=false&pooling=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 1800, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 100, maxStatements -> 150, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> true, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
main.main (java line: 28)
java.lang.RuntimeException: java.lang.RuntimeException: java.sql.SQLException: You can't operate on a closed Connection!!!
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
    at peacemaker.sc4grabber.main.main(main.java:28)
Caused by: java.lang.RuntimeException: java.sql.SQLException: You can't operate on a closed Connection!!!
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.objects.Timer$TickTack$1.run(Timer.java:135)
    at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
    at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
    at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:180)
    at peacemaker.sc4grabber.main._appstart(main.java:157)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.D
elegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    ... 2 more
Caused by: java.sql.SQLException: You can't operate on a closed Connection!!!
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
    at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement(NewProxyConnection.java:576)
    at anywheresoftware.b4j.objects.SQL.ExecQuery2(SQL.java:365)
    at anywheresoftware.b4j.objects.SQL.ExecQuery(SQL.java:353)
    at peacemaker.sc4grabber.main$ResumableSub_timSystem_Tick.resume(main.java:826)
    at peacemaker.sc4grabber.main._timsystem_tick(main.java:728)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    ... 12 more
Caused by: java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement(NewProxyConnection.java:540)
    ... 21 more
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
yes.
Unclear
1) why new connections are created on background without my calling the pool
2) and why it's closed.
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Let's return to the previous state... remove from public the resultset (Dim names as resultset / that was no move - was just publishing the name wanna used...) - have it again with the query at the point you had it...

and please comment / rem the lines i ve said to check what happens...
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Already tried this
B4X:
Sub timSystem_Tick
    timSystem.Enabled = False
    
    If machine_id = 0 Then
        Dim filter As Map: filter.Initialize
        filter.Put("scanner_name", others.Get_DeviceID)
        webapi1.API_LOAD("scanners", filter)
        Wait For API_LOADED (L As List)
        If L.Size > 0 Then
            Dim machine_id As Int = L.Get(0).As(Map).Get("machine_id")
            Log("machine_id = " & machine_id)
            timFTPupload_Tick
        Else
            Log("machine_id trouble !")
        End If   

    Else
        Dim names As ResultSet = db.SQL.ExecQuery("SELECT * FROM " & db.DBT_NAMES & " WHERE sent = '0' LIMIT 1")
        Do While names.NextRow
            Dim name As String = names.GetString("name")
            Log("Sending ... " & name)
            
' removed all
            
            Log("Sent: " & name)
            db.SQL.ExecNonQuery("UPDATE " & db.DBT_NAMES & " SET sent = '1' WHERE name = '" & name & "' LIMIT 1")    'sent status finally
        Loop
        names.Close
        names = Null
    End If

    timSystem.Enabled = True
End Sub
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
what is doing - are you getting error?


REM also those:
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Already tried, commented whole timer - here another error:
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Are you sure that you are not opening the db... in other point... or other resultsets ?...

did you made a reboot... May be you need to close somewhere the db (when shutdown the app/exit somehow...)...

but make a reboot at your pc...
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Many other resultsets, all are closed at finish.
DB opening is just in "db" module, SINGLE POINT:

B4X:
    Sub Process_Globals
    Dim SQL As SQL
    end sub
   
    Public Sub InitializeDB
    DBM.InitializeMySQL($"jdbc:mysql://${DBLocation}/${DBname}?characterEncoding=utf8&allowPublicKeyRetrieval=false&autoReconnect=false&requireSSL=false&useSSL=false&pooling=true"$, DBUsername, DBPassword, 100)
    SQL = DBM.GetSQL
    ...

DBM you should know what it is from ABMaterial.

And every where used as db.SQL for requests.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Yes. Server app with ABMaterial interface, but here it's not so relevant, IMHO.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
B4X:
SQL.Initialize2("com.mysql.jdbc.Driver", $"jdbc:mysql://${DBLocation}/${DBname}?characterEncoding=utf8&allowPublicKeyRetrieval=false&autoReconnect=false&requireSSL=false&useSSL=false&pooling=true"$, DBUsername, DBPassword)

works OK now, with commented timer sub.
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
Just to share my experience.
I did not understand how MySQL connection pooling works when I developed Web API Template version 1. That time ilan has pointed out the issue and I fixed it in v1.11 by not closing the pool. For SQLite, it is a different case where we need to close the database connection.
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
what did you changed ?

so test with commented the others (with sleep... and first if ...) to see if have prob with resultset... and if works ok... if works ok.. and you have problem with commented... try to use waitfor.. right
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…