Getting [SQLITE_BUSY] database file is locked with select statements
Asked Answered
C

12

43

If I run multiple threads against my web app I get:

java.sql.SQLException: [SQLITE_BUSY]  The database file is locked (database is locked)
    at org.sqlite.DB.newSQLException(DB.java:383)
    at org.sqlite.DB.newSQLException(DB.java:387)
    at org.sqlite.DB.execute(DB.java:339)
    at org.sqlite.PrepStmt.executeQuery(PrepStmt.java:75)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)

I do know that only one thread can write to a sqlite database but I'm only reading from the database. So why do I get this error message ?

BTW: My connection pool looks like this:

<bean class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}" />
    <property name="url" value="${database.url}" />
    <property name="username" value="${database.username}" />
    <property name="password" value="${database.password}" />
    <property name="initialSize" value="1" />
    <property name="maxActive" value="2" />
    <property name="maxIdle" value="1" />
    <property name="poolPreparedStatements" value="true" />
</bean>

The setup is: Java 1.6, Tomcat 7.0.34, Spring 3.2, Hibernate 3.6.9 and sqlite3 3.7.2

Regards Roger

Chapbook answered 15/12, 2012 at 9:24 Comment(1)
Possible duplicate of SQLITE_BUSY The database file is locked (database is locked) in wicketCounsellor
P
33

After some googling I found that it is a bad practice to use multiple connections when connecting to SQLite. See

http://touchlabblog.tumblr.com/post/24474398246/android-sqlite-locking

Set your poolsize maxactive to 1 and try out.

Pyrrho answered 15/12, 2012 at 11:48 Comment(2)
Yes that works. But I still do not understand why the file is locked although only select statements are executed.Chapbook
@rogergl: Try getting a connection with SQLiteOpenHelper#getReadableDatabase(). Link: developer.android.com/reference/android/database/sqlite/…Pyrrho
K
28

For anyone who's having issues with it in WSL2:

Happened to me when I was using WSL2 & Datagrip, even tho the database wasn't busy.

It turns out that Datagrip has tried to connect to the database file that existed inside WSL2 via Windows' sqlite3.

Moving the file from WSL2 to a Windows file directory seems to solve this issue

Kaftan answered 5/1, 2022 at 16:51 Comment(2)
This solution worked for me, too: copying the file from the WSL2 filesystem to the Windows filesystem fixed the connection problem. In my case I was trying to connect with DBeaver, so the problem&solution is not limited to Datagrip. (Perhaps both programs use the same database driver library.)Capture
I ran into the same issue. It's tracked here (youtrack.jetbrains.com/issue/DBE-11014) on the DataGrip issue tracker. Addendum: The bug seems to be in WSL, not supportng file locking: github.com/microsoft/WSL/issues/4689Alum
A
13

There should be only ONE connection with your application. you can use this to ensure.

public class SqliteHelper {
private static Connection c = null;
public static Connection getConn() throws Exception {
    if(c == null){
    Class.forName("org.sqlite.JDBC");
    c = DriverManager.getConnection("jdbc:sqlite:D:/test.db");
    }
    return c;
    }
}
Aquarist answered 15/6, 2014 at 18:27 Comment(0)
B
9

Note also that this may happen if you accidentally forget to close your connection:

Connection connection;
try {
  Statement statement = connection.createStatement();
  ResultSet resultSet = statement.executeQuery(QUERY);
  if (resultSet.next()) { /* do something */ }
catch (SQLException e) { /* handle exception */ }
finally {
  if (connection != null) {
    try {
      connection.close(); // <-- This is important
    } catch (SQLException e) {
      /* handle exception */
    }
  }
}

While the first database connection may work well once the server is started, subsequent queries may not, depending on how the connection pool is configured.

Benedikta answered 21/10, 2014 at 20:12 Comment(0)
B
3

Everytime you establish a connection make sure to close it after the work is done, It worked for me like if you are using

Connection con = null;
PreparedStatement pst = con.prepareStatement("...query... "); 
/*
 do some stuff 
*/
pst.executeQuery();
pst.close();
con.close();
Bloodroot answered 1/5, 2018 at 5:15 Comment(1)
I got this issue when executing two prepared statements one after the other. The solution was to close the prepared statement, just like you suggested.Artemas
K
1

I experienced the same problem, even though all connections, resulsets and statements were closed, I still had the error. The problem for me was using the DB browser plugin in Intellij to visualize and manage tables. Disconnecting the database from this tool solved the problem. So make sure that no external tool is connecting to the database and locking tables.

Kingsly answered 10/11, 2020 at 7:52 Comment(1)
this at-least help me. tks for the answer.Uncharitable
C
1

In my case, there are thread using sqlite connection in the background, which caused this error.

  1. close sqlitebrowser
  2. close electron app ( maybe need restart)
  3. re-run your program.
Carlocarload answered 18/4, 2021 at 11:41 Comment(0)
K
0

For me the problem was that I was opening too much Sessions So I made the session field in my DAO class static

Katey answered 7/12, 2018 at 16:49 Comment(0)
R
0

Thanks from bowman han, I added a piece of code to his solution and it worked for me.

private static Connection c = null;
public static Connection connect() throws Exception {

    if (c == null) {
        c = (Connection) DriverManager.getConnection(url);
    } else {
        c.close();
        c = (Connection) DriverManager.getConnection(url);
    }
    return c;
}
Romona answered 9/11, 2019 at 11:21 Comment(0)
H
0

You have opened another application containing the database, Try to close that application and run your program again. This worked for me

Heavyarmed answered 26/8, 2021 at 23:23 Comment(1)
Moreover, close the resultsSet and the prepareStatement after query or you can use the “try with resource” which is very helpfulGezira
A
0

Always work with me

private static Connection con = null; 

public static Connection sqlite(){

        try {
            if (con != null) {
                con.close();
            }
            return   con =(Connection) DriverManager.getConnection(url);
        } catch (SQLException ex) {
            throw new RuntimeException( ex);
        }

    }
Allow answered 24/7 at 11:6 Comment(0)
P
-2

Try @Transactional(readonly=true) for those methods that only do reads. Maybe that works for you.

Pyrrho answered 15/12, 2012 at 9:30 Comment(1)
This is also recommended within SQLite documentation as one of several steps to reduce the occurrence of this situation. The first step would be to ensure everything is closed. Also should check that the database supports threading (default is on) FULLMUTEXDahna

© 2022 - 2024 — McMap. All rights reserved.