Database per Thread

I normally have one database per session. And that database gets referenced throughout the project in libraries etc…

dim rs as recordSet = [b]session.db[/b].sqlselect(sql)

This works fine but I’m going to start putting some querying in threads.
If a different thread is using the same db connection, will this cause issues?
I can have the called methods generate there own database but I dont want tons of databases being created, connected, disconnected and destroyed every time I do something.
For example, I might save 10 objects and I would like to use one db connection to do it rather than 10.
But I also don’t want to add a “db as database” parameter to all of my utility and class methods.

Is there a way to create a session.db property be computed so that if its the main thread the user keeps getting the same database and if its in a thread, the entire thread will get one unique db connection and this will disconnect when the thread goes out of scope?

please use one connection per session.
And as I think each session has one thread, that’s normally okay.
Other threads may need extra connections to keep transactions and other state separated.

This is what I do already.

My question really involves if there is some sort of computed property I can use that when accessed through a thread it generates one continuous database connection to be used from all methods that call the property via thread. (???)

I just figured this out this week for ActiveRecord in Web Applications so forgive the web app specific terminology.

In this first function I get the db from the Namespace. Desktop should probably do the same as web (haven’t gotten there yet) but in web looks for Session object, if not, then it looks at the current threadID and will go through the gyrations of figuring out which connection to use.

[code]Protected Function db() As SQLiteDatabase
#if TargetDesktop then
return app.db

#elseif TargetWeb then

if session.Available then
  //First, look to see if session is available.
  return session.db
  
else
  
  //Second look at the current thread
  if app.CurrentThread = nil then
    //Main thread if current thread is nil
    return app.db
    
  else
    //In a thread.  Will reuse existing connection if it exists
    return AddHandleSpecialURLConnection
  end
  
end

#Endif
End Function
[/code]

[code]Protected Function AddHandleSpecialURLConnection() As SQLiteDatabase
//Get the Current Thread ID
dim iThreadID as integer = app.CurrentThread.ThreadID

//Now create a db object
dim dbHandleSpecialURL as SQLiteDatabase

dim bConnectionFound as boolean
for each oConnection as clsDBConnection in aroConnectionPool
//Just in case thread id’s are reused quicker than we expect check to make sure the thread
//it was created in is still valid.
if oConnection.iThreadID = iThreadID and oConnection.oThreadWeakRef.value <> nil then
dbHandleSpecialURL = oConnection.DB
bConnectionFound = true
exit
end
next

if bConnectionFound = false then
//Not in the existing pool. Create a new one.
dbHandleSpecialURL = Data.OpenDB

dim oConnection as new clsDBConnection
oConnection.iThreadID = iThreadID
oConnection.oThreadWeakRef = new WeakRef(app.CurrentThread)
oConnection.DB = dbHandleSpecialURL
aroConnectionPool.Append oConnection

end

//---------Remove old Connections---------------
for i as integer = aroConnectionPool.Ubound downto 0
dim oConnection as clsDBConnection = aroConnectionPool(i)
if oConnection.oThreadWeakRef.Value = nil then
//Thread is dead. Kill the conneciton object
aroConnectionPool.Remove i
end
next

return dbHandleSpecialURL
End Function
[/code]

clsDBConnection has 3 properties:
db as SQLiteDatabase
iThreadID as integer
oThreadWeakRef as WeakRef

There are probably more efficient ways of doing this and it’s not been extensively tested. If you find something let me know!

[quote=133316:@Brock Nash]I normally have one database per session. And that database gets referenced throughout the project in libraries etc…

dim rs as recordSet = [b]session.db[/b].sqlselect(sql)

This works fine but I’m going to start putting some querying in threads.
If a different thread is using the same db connection, will this cause issues?[/quote]
Yes
Never share db references across threads

[quote=133324:@Bob Keeney]I just figured this out this week for ActiveRecord in Web Applications so forgive the web app specific terminology.

There are probably more efficient ways of doing this and it’s not been extensively tested. If you find something let me know![/quote]

@Bob Keeney
Yes! Thank you - thank you! This is exactly what I was looking for. I’ll definitely work with this and post here if I come up with any improvements.

Here’s my thoughts so far.
The app.CurrentThread.ThreadID is definitely key.
Just curious if there was a way to get the actual thread object via the thread ID?
If so I could subclass a thread into a WebSessionThread and have a session property on that subclassed thread instead of managing a pool. Would make the cleanup automatic too.

Short of iterating runtime objects I don’t think so

You can’t iterate the WebSession threads. I’ve tried that and they don’t appear in the list. I chatted with Greg about it and he said something about internal threads won’t appear. That’s why we had to go with the weakref option.

ah right - I don’t work on the web framework much so there are details like that I forget :slight_smile:
It’s why you don’t see me answer too many web edition q’s.

Would it be any better/worse to use a dictionary to get the database for a thread versus an array?

the objects you get via Runtime Objectiterator are only objects from public classes.

I don’t think it matters much. Use what you’re more comfortable with.

In my case the database they connect to is dependent upon the session. I’m already dealing with a scaled DB environment. Because the thread needs to already know which Database it is connecting to, I’m subclassing the thread to take in a db from the constructor and save a weak ref to a dictionary so it can be looked up.

I probably don’t need the weak ref and I could cleanup the dictionary database reference at the end of the thread’s run. Thoughts?

Why not just add the database as a property to the session? My whole workaround was for when ActiveRecord is used outside of a session.

It already is.

Do threads know about what session created them though? What if I have the database running a query on a main session thread and I have a different thread running some background processing for that user. Doesn’t this need to be a different database connection?

In that case I would subclass the thread and put whatever properties you need to keep things straight. If you care which thread belongs to which session (or visa versa) then pass that into the thread when you instantiate it. Otherwise, when the thread completes the database reference will go out of scope and close.

I might be missing something (not enough caffeine yet) but I think you’re okay. I get suspicious when things get too complicated and think perhaps I’m overthinking the problem.

@Bob Keeney I think we all do that. If I have to grab paper (or whiteboard) and start drawing out diagrams on how things interconnect, I know I have over thought/complicated the situation.