18

I have a python script which uses the latest sqlalchemy. When i use sqlite,only sqlite, other db works well, i get the following error:

sqlalchemy.exc.OperationalError: (OperationalError) database is locked u'SELECT blabla....

Any hint?

Example from my code (simplified), i have several methods like this, to select, update and delete things:

class MyDb(object):
    def __init__(self):
        engine = create_engine("sqlite:///file", poolclass=NullPool, pool_threadlocal=True)
        engine.pool_size=1
        engine.pool_timeout = 60
        self.sess = sessionmaker(bind=engine)

    def del_stuff(self):
        sess = self.sess()
        sess.query(Stuff).delete()
        try:
            sess.commit()
        except:
            sess.rollback()

    def set_stuff(self, id, bar):
        sess = self.sess()
        sess.query(Foo).get(id).bar = bar
        try:
            sess.commit()
        except:
            sess.rollback()
tapioco123
  • 3,235
  • 10
  • 36
  • 42

14 Answers14

35

SQLite locks the database when a write is made to it, such as when an UPDATE, INSERT or DELETE is sent. When using the ORM, these get sent on flush. The database will remain locked until there is a COMMIT or ROLLBACK.

I've mostly seen the "database is locked" error in multi-threading situations. One thread will lock the database and another thread will attempt a write of its own. If the first thread doesn't release the lock within the timeout period (4-5 seconds by default, if I recall) the OperationalError is raised on the second thread.

It can be tricky to know when a flush, and therefore a write is made to the database when the session has autoflush=True (the default setting) since any query will cause a flush. Sometimes turning on the SQL logging can help clarify when things are happening:

logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

There is some relevant documentation here: http://docs.sqlalchemy.org/en/rel_0_9/dialects/sqlite.html#database-locking-behavior-concurrency

Eric Smith
  • 2,739
  • 2
  • 30
  • 29
10

Check any commits pending in database through any developer tools.

As everyone told above sqlite databases only allow one process to access it at a time. In my case, I am using DB browser for sqlite and in the same, I didn't commit a query. That's also lock the DB and will not allow the application to write to database.

recnac
  • 3,744
  • 6
  • 24
  • 46
Bino
  • 744
  • 15
  • 22
6

sqlite databases only allow one process to access it at a time. Perhaps you have a separate process using the database?

Y.H Wong
  • 7,151
  • 3
  • 33
  • 35
4

you should use a single session across all objects in a thread. sqlite really doesn't like multiple connections, and sqlalchemy is effectively a connection per session (it looks like you may have a session for each class, which implies multiple sessions in a single thread).

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
4

In my case with quite a simple logic and no multithreading the source of the issue appeared to be quite banal...

'SQLite is not designed for a high level of write concurrency. The database itself, being a file, is locked completely during write operations within transactions, meaning exactly one “connection” (in reality a file handle) has exclusive access to the database during this period - all other “connections” will be blocked during this time.'

... so that 'enlightened' an idea: disconnect DB Browser which I used to check the db during the work. And it worked well. So if that is possibly your case - check if you are not connected to your sqlite via other tool ;)

3

Check your code for these points:

  1. Instance of MyDb must be one for all application lifetime. MyDb must be a singleton.
  2. Try using 'plain' strategy for engine but not pool_threadlocal=True
  3. Close session on each logical request is done.

For example:

def set_stuff(self, id, bar):
    sess = self.sess()
    sess.query(Foo).get(id).bar = bar
    try:
        sess.commit()
    except:
        sess.rollback()
    finally:
        sess.close()
J0e3gan
  • 8,740
  • 10
  • 53
  • 80
estin
  • 3,051
  • 1
  • 24
  • 31
2

also met the same problem:

  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 590, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) database is locked
[SQL: DELETE FROM vminds4 WHERE vminds4.id = ?]
[parameters: (2,)]
(Background on this error at: http://sqlalche.me/e/e3q8)

Finally, get here, bacause I just open another terminal open the sqlite3 files and after I closed the window, it works!

ccc77
  • 21
  • 1
2

I had the same error, which I could fix by:

db.session.close_all()

For me, the error occured due to too many open db connections, since I used the Spyder console instead of the terminal

Heinrich G
  • 31
  • 5
0

just use StaticPool. and also follow this answer (scoped_session): https://stackoverflow.com/a/9621251

create_engine(DB_PATH, echo=False, poolclass=StaticPool, connect_args={'check_same_thread': False})

Ali
  • 1
0

For future comers, in my case, the pandas to_sql function (with a sqlalchemy connection string) to write to a sqlite file on a CIFS shared mount was failing. The same function would work on an ext4 disk. The fix was to add nobrl to the options in /etc/fstab, unmounting, then re-mounting the disk. Then the to_sql command worked.

Shadi
  • 9,742
  • 4
  • 43
  • 65
0

In my case, my Antivirus thought that flask was a threat and locked the database. I solved it by excluding that flask process from the security check.

Albert
  • 1
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 12 '22 at 06:11
0

If you have any database explorer like DB Browser for SQLite holding a lock on the db file, close any connection to the db there or just exit the app all together. Only one app can have the SQLite file open (connected) at a given time to maintain ACID

Joseph Tam
  • 1
  • 1
  • 2
-2

My answer is only for those who are experimenting with the flask database and they are ready to delete their database for removing the database lock. If you are experimenting, then surely you can add data to tables again by running a python script.

Here we go....

  1. delete the data.sqlite file present in your flask project

  2. delete the migrations folder present in your flask project

  3. Now run following commands to create a new database:

    • flask db init
    • flask db migrate -m "tables"
    • flask db upgrade
  4. Now you can run your python script to add data to the database or you can manually add data to tables using python promt/flask shell.

Yashwant Kumar
  • 407
  • 4
  • 5
-4

This might happen if there are duplicate records in the table

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140