How to use SQLite in a multi-threaded application?
Check out this link. The easiest way is to do the locking yourself, and to avoid sharing the connection between threads. Another good resource can be found here, and it concludes with:
Make sure you're compiling SQLite with -DTHREADSAFE=1.
Make sure that each thread opens the database file and keeps its own sqlite structure.
Make sure you handle the likely possibility that one or more threads collide when they access the db file at the same time: handle SQLITE_BUSY appropriately.
Make sure you enclose within transactions the commands that modify the database file, like INSERT, UPDATE, DELETE, and others.
using sqlite3 in multithreading
One connection has exactly one transaction, so your program is likely to blow up when multiple threads try to share the same connection without locking around all transactions.
Use one connection per thread.
(If you need high concurrency, SQLite might not be the best choice.)
SQLite transactions in a multi-threaded application
After playing around with this, I have figured out that my earlier conclusion regarding needing to share a single connection across threads was wrong. Each thread now:
- Uses a special singleton class called
ConnectionManager
that createsSQLiteConnection
instances, opens them, and configures common settings that have to be set after each connection is opened. - Creates a new connection before it accesses the database by calling a method in the
ConnectionManager
class. - Starts and manages any transactions in the usual way.
- Closes and disposes of the
SQLiteConnection
in the usual way.
The ConnectionManager
class allows all code that needs to connect to the database to obtain their connection, with all of the database settings set in a consistent manner. Most of the properties my code needs to set are actually in the connection string, but there is one that can't be specified there, so I needed another mechanism. Here's what the ConnectionManager
looks like:
public class ConnectionManager {
public int BusyTimeout { get; set; }
public static ConnectionManager Instance {
get {
if ( iInstance == null ) {
lock ( instanceLock ) {
if ( iInstance == null )
iInstance = new ConnectionManager();
}
}
return iInstance;
}
}
private static ConnectionManager iInstance = null;
private static object instanceLock;
private ConnectionManager() {
BusyTimeout = Convert.ToInt32( TimeSpan.FromMinutes( 2 ).TotalMilliseconds );
}
static ConnectionManager() {
instanceLock = new object();
}
public SQLiteConnection CreateConnection( string connectionString ) {
SQLiteConnection connection = new SQLiteConnection( connectionString );
connection.Open();
using ( SQLiteCommand command = connection.CreateCommand() ) {
command.CommandText = string.Format( "PRAGMA busy_timeout={0}", BusyTimeout );
command.ExecuteNonQuery();
}
return connection;
}
}
To use the ConnectionManager
class, either an instance variable or a local variable is set to a copy of the singleton instance like this:
_connectionManager = ConnectionManager.Instance;
To obtain and use a database connection, code like this is used in each thread:
using ( SQLiteConnection connetion = _connectionManager.CreateConnection( connectionString ) {
// Thread's database operation code here
}
It turns out the real trick to making it work was to set the busy_timeout pragma to something longer than the default. SQLite internally is fully thread-safe and serializes requests on its own, so your code just needs to tell SQLite to wait for any currently executing operation to finish. Our code is already structured so that failures in the database engine for any reason cause the operation to be retried after waiting a few seconds, so this works well.
The default 2 minute wait time is long enough for 99.99% of all operations to finish. Really, if something take longer than 2 minutes to complete, we need to revisit that area and make it faster any way.
How to share single SQLite connection in multi-threaded Python application
It's not safe to share a connection between threads; at the very least you need to use a lock to serialize access. Do also read http://docs.python.org/2/library/sqlite3.html#multithreading as older SQLite versions have more issues still.
The check_same_thread
option appears deliberately under-documented in that respect, see http://bugs.python.org/issue16509.
You could use a connection per thread instead, or look to SQLAlchemy for a connection pool (and a very efficient statement-of-work and queuing system to boot).
Getting SQLite3 to work with multiple threads
The Python sqlite3
module has a threadsafety
level of 1, which means that although you can't share database connections between threads, multiple threads can use the module simultaneously. So, you could have each thread create its own connection to the database.
The problem with this approach is that SQLite has poor write concurrency, so having multiple threads doing a ton of INSERT
s at once will give you the dreaded “database is locked” error. You can improve things somewhat by using PRAGMA JOURNAL_MODE = 'WAL'
, but that only goes so far.
If performance is an issue and switching to a client-server database isn't an option, then what you'll probably have to do is keep an in-memory cache of your URLs, and arrange your program so that you have one thread that syncs this cache with the SQLite database.
How to set threading mode in SQLite Java
From the link you posted:
The default mode is serialized.
If you want to explicitly select the serialized mode (or switch back to it), then use SQLiteOpenMode.FULLMUTEX
as is also described in the docs.
How should I handle multiple threads accessing a sqlite database in Python?
I was able to write something that meets my needs with the help of this article: http://effbot.org/zone/python-with-statement.htm
My code looks like this:
import threading
import sqlite3
class LockableSqliteConnection(object):
def __init__(self, dburi):
self.lock = threading.Lock()
self.connection = sqlite3.connect(dburi, uri=True, check_same_thread=False)
self.cursor = None
def __enter__(self):
self.lock.acquire()
self.cursor = self.connection.cursor()
return self
def __exit__(self, type, value, traceback):
self.lock.release()
self.connection.commit()
if self.cursor is not None:
self.cursor.close()
self.cursor = None
Objects of this class are now directly usable with the with
statement:
dburi = "file:TESTING_MEMORY_DB?mode=memory&cache=shared"
lsc = LockableSqliteConnection(dburi)
with lsc:
lsc.cursor.execute("SQL")
It also conveniently opens a cursor for me and automatically commits changes I make to the database, which means that code which calls my new class is shorter. That's nice, but automatically committing database changes might not actually be the best idea... In more complex scenarios where you might want to start a transaction and then roll it back partway through, that functionality might cause trouble. My SQL needs are very simple, however, and I never roll back, so I've left it in my project for now.
Multithreading in C# sqlite
A clever use of ReaderWriterLockSlim
will definitely help you improve performance.
private ReaderWriterLockSlim _readerWriterLock = new ReaderWriterLockSlim();
private DataTable RunSelectSQL(string Sql)
{
DataTable selectDataTable = null;
try
{
_readerWriterLock.EnterReadLock();
//Function to acess your database and return the selected results
}
finally
{
_readerWriterLock.ExitReadLock();
}
return selectDataTable;
}
private DataTable RunInsertSQL(string Sql)
{
DataTable selectDataTable = null;
bool isbreaked = false;
try
{
_readerWriterLock.EnterWriteLock();
if (_readerWriterLock.WaitingReadCount > 0)
{
isbreaked = true;
}
else
{
//Function to insert data in your database
}
}
finally
{
_readerWriterLock.ExitWriteLock();
}
if (isbreaked)
{
Thread.Sleep(10);
return RunInsertSQL(Sql);
}
return selectDataTable;
}
Try this it will, improve your responsiveness and you have Select
query to fire having higher priority over Insert
SQL.
Please note, if some insertion is already running then Select will at least wait for that insertion to complete.
This code will always give priority to SELECT
over INSERT
.
One more point, never perform the long ongoing operation on main thread like you have selecting from database, rather perform the operation in background and then reflect the latest results on UI using main thread. This will ensure that your UI will never freeze.
EDIT There can be a starvation case where all INSERT
may be waiting, if there are continuous SELECT
queries being fired without any gap.
But I believe in your case, this will not happen as the UI
will not always be refreshing to get the latest changes so frequently without any time slice in between.
Related Topics
Passing Shared Pointers as Arguments
How to Get the Gl Library/Headers
Boost Asio Ssl Async_Shutdown Always Finishes with an Error
What Are the Differences Between Overriding Virtual Functions and Hiding Non-Virtual Functions
All Combinations of K Elements Out of N
I Cannot Pass Lambda as Std::Function
Is a Constexpr Array Necessarily Odr-Used When Subscripted
Std::Vector Iterator Invalidation
Division by Zero: Undefined Behavior or Implementation Defined in C And/Or C++
Visual Studio Code Formatting for "{ }"
How to Make a Multiple-Read/Single-Write Lock from More Basic Synchronization Primitives
Replacing Ld with Gold - Any Experience
How to Identify the File Content as Ascii or Binary
C/C++ Changing the Value of a Const
C++ Threads, Std::System_Error - Operation Not Permitted