131

I have a SQLite database that is used by two processes. I am wondering, with the most recent version of SQLite, while one process (connection) starts a transaction to write to the database will the other process be able to read from the database simultaneously?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
sean717
  • 11,759
  • 20
  • 66
  • 90

3 Answers3

210

I collected information from various sources, mostly from sqlite.org, and put them together:

First, by default, multiple processes can have the same SQLite database open at the same time, and several read accesses can be satisfied in parallel.

In case of writing, a single write to the database locks the database for a short time, nothing, even reading, can access the database file at all.

Beginning with version 3.7.0, a new “Write Ahead Logging” (WAL) option is available, in which reading and writing can proceed concurrently.

By default, WAL is not enabled. To turn WAL on, refer to the SQLite documentation.

Frédéric
  • 9,364
  • 3
  • 62
  • 112
sean717
  • 11,759
  • 20
  • 66
  • 90
  • 1
    so hypothetically if you had to solve a problem where you wanted data locally without making it accessible for the general public but the ability to write multiple files in parallel, you will need one database file per such write so that multiple writes may happen concurrently. is it? I know multiple files is usually frowned upon but I am trying to figure out a way to do multiple writes from a celery task without using a server side database as I need the data only for local computations – PirateApp May 05 '18 at 07:51
  • 1
    There is a pragma, [locking_mode=exclusive](https://www.sqlite.org/pragma.html#pragma_locking_mode) that can be used to lock the database to a single process, if you want to prevent this functionality. – Scovetta Dec 13 '19 at 19:03
31

SQLite3 explicitly allows multiple connections:

(5) Can multiple applications or multiple instances of the same application access a single database file at the same time?

Multiple processes can have the same database open at the same time. Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.

For sharing connections, use SQLite3 shared cache:

Starting with version 3.3.0, SQLite includes a special "shared-cache" mode (disabled by default)

In version 3.5.0, shared-cache mode was modified so that the same cache can be shared across an entire process rather than just within a single thread.

5.0 Enabling Shared-Cache Mode

Shared-cache mode is enabled on a per-process basis. Using the C interface, the following API can be used to globally enable or disable shared-cache mode:

int sqlite3_enable_shared_cache(int);

Each call sqlite3_enable_shared_cache() effects subsequent database connections created using sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). Database connections that already exist are unaffected. Each call to sqlite3_enable_shared_cache() overrides all previous calls within the same process.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Arun
  • 19,750
  • 10
  • 51
  • 60
7

I had a similar code architecture as you. I used a single SQLite database which process A read from, while process B wrote to it concurrently based on events. (In python 3.10.2 using the most up to date sqlite3 version). Process B was continually updating the database, while process A was reading from it to check data. My issue was that it was working in debug mode, but not in "release" mode.

In order to solve my particular problem I used Write Ahead Logging, which is referenced in previous answers. After creating my database in Process B (write mode) I added the line:

cur.execute('PRAGMA journal_mode=wal') where cur is the cursor object created from establishing connection.

This set the journal to wal mode which allows for concurrent access for multiple reads (but only one write). In Process A, where I was reading the data, before connecting to the same database I included:

time.sleep(0.5)

Setting a sleep timer before a connection was made to the same database fixed my issue with it not working in "release" mode.

In my case: I did not have to manually set any checkpoints, locks, or transactions. Your use case might be different than mine however, so research is most likely required. Nevertheless, I hope this post helps and saves everyone some time!

jack
  • 71
  • 1
  • 3
  • What do you mean by "debug" and "release" mode? Are you talking about the build flavors, e.g., `configure CPPFLAGS=-DSQLITE_DEBUG`? Also, why do your readers have to sleep some arbitrary amount to get them to work? This was a useful post; thanks. – Jim Sep 07 '22 at 20:17
  • 1
    In my IDE (vs code) I can run the program using the debugger (debug mode) or normally by simply pressing the play button where the program runs until completion(release mode). Not sure why sleeping made it work. Maybe it helps the programs sync up, nevertheless it was a lucky debug technique. Threads and locks could be another strategy to use. See article here: https://medium.com/swlh/getting-started-with-concurrency-in-python-part-i-threads-locks-50b20dbd8e7c – jack Sep 09 '22 at 01:04