Reputation: 3781
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
Upvotes: 45
Views: 107897
Reputation: 554
I had this issue with SqlDelight, I was using nested transactions.
It turned out some DI code was creating multiple instances of the AndroidSqliteDriver
, which were likely not correctly closed. I fixed it by making sure AndroidSqliteDriver
was only instantiated once.
Upvotes: 0
Reputation: 966
The most elegant and worked solution that I found here is:
move the database file to a path accessible from both WSL2 and Windows.
Steps:
Command:
ln -s /mnt/c/Users/Tanut/Desktop/foo.db ./foo.db
Upvotes: 1
Reputation: 1
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);
}
}
Upvotes: 0
Reputation: 11508
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
Upvotes: 32
You have opened another application containing the database, Try to close that application and run your program again. This worked for me
Upvotes: 0
Reputation: 21557
In my case, there are thread using sqlite connection in the background, which caused this error.
Upvotes: 1
Reputation: 11
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.
Upvotes: 1
Reputation: 2092
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;
}
Upvotes: 0
Reputation: 106
For me the problem was that I was opening too much Sessions So I made the session field in my DAO class static
Upvotes: 0
Reputation: 20359
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();
Upvotes: 3
Reputation: 2625
Try @Transactional(readonly=true)
for those methods that only do reads. Maybe that works for you.
Upvotes: -1
Reputation: 962
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.
Upvotes: 9
Reputation: 1135
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;
}
}
Upvotes: 13
Reputation: 2625
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.
Upvotes: 34