Getting [SQLITE_BUSY] database file is locked with select statements - java

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

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.

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

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;
}
}

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.

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();

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.

In my case, there are thread using sqlite connection in the background, which caused this error.
close sqlitebrowser
close electron app ( maybe need restart)
re-run your program.

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

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;
}

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

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

Related

Release open Connection in Java 8

I have a JSP/Servlet based application, the database team is complaining about the increase in open database connection.I suspect that the connection is not closed after use.
I want to make some code changes by initializing the connection string in try catch block as suggested in Java 8
I have tried closing the connection in final block which is working fine
here is the code i want to implement , Will this fix the issue?Is there any other way to close the open connections after use with little code change?
try(Connection con = DBConnectivity.openConnectionThread();
PreparedStatement ps1 = con.prepareStatement(sql1)) {
-----
------
}
You should close also PreparedStatement
try(Connection con = DBConnectivity.openConnectionThread();
PreparedStatement ps1 = con.prepareStatement(sql1))
{
-----
------
}

Not able to connect SQL server in Groovy

I am trying to connect to a SQL server using an automation tool (Workfusion Studio), which uses selenium and groovy.I am getting an error "No suitable driver found for jdbc:sqlserver:/XXXXXXXXXXXXXX" when I try to create a connection.
The code I am using is below:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://web-harvest.sourceforge.net/schema/1.0/config" scriptlang="groovy">
<selenium-flow>
<selenium name="seleniumDriver" browser="chrome" close-on-completion="true" start-in-private="true">
<script><![CDATA[
import java.sql.*;
this.class.classLoader.addURL(new URL("http://clojars.org/repo/com/microsoft/sqlserver/sqljdbc4/4.0/sqljdbc4-4.0.jar"));
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String dbURL = "jdbc:sqlserver://SERVER_NAME:1433;databaseName =DATABASE_NAME;";
String userName = "USER_NAME";
String password = "PASSWORD";
Connection con = DriverManager.getConnection(dbURL, userName, password);
]]></script>
</selenium> 
</selenium-flow>
</config>
Please help resolve the issue.
The JDBC connection is performed through global ClassLoader, so it does not see libs added to local ClassLoader.
You can add the driver jar globally to Control Tower tomcat:
$INSTALL_DIR/apps/webapps/tomcat/lib
For the logic to work in WorkFusion Studio, refer to the Eclipse guides on how to add external jar.
As a workaround (not recommended for production code), the following trick can be performed:
<script><![CDATA[
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
} catch (ClassNotFoundException expected) {
groovy.lang.GroovyShell.class.classLoader.addURL(new URL("http://clojars.org/repo/com/microsoft/sqlserver/sqljdbc4/4.0/sqljdbc4-4.0.jar"));
}
]]></script>
More efficient way to execute queries is as following (will properly close the DB connection, etc.):
<database connection="jdbc:sqlserver://hostname:6501;DatabaseName=database"
jdbcclass="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="user" password="securepassword">
select first_name from actor
</database>

org.h2.jdbc.JdbcSQLException: Database may be already in use: null. Possible solutions: close all other connection(s); use the server mode [90020-193]

I want to use H2 database in embedded mode and not on server mode.
But after only one transaction I am getting error that file is locked.
I have tried appending DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO after url but it is not working.
Is there any solution for this?
<property name="connection.driver_class">org.h2.Driver</property>
<!-- <property name="connection.url">jdbc:h2:./test;AUTO_SERVER=TRUE</property> -->
<property name="connection.url">jdbc:h2:./test;DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO</property>
<property name="connection.username">sa</property>
<property name="connection.password">sa</property>
here is the code that saves user object.
SessionFactory factory = new Configuration().configure("/resources/hibernate.cfg.xml").buildSessionFactory();
Session session = factory.openSession();
session.beginTransaction();
UserVO user = new UserVO();
user.setUserId("4");
user.setUserName("Fourth User");
session.save(user);
session.getTransaction().commit();
session.clear();
session.close();

Programmatically enabling remote jmx monitoring

I am attempting to enable my core java application for remote accessibility via JMX.
However, two restrictions are making it harder than it should be.
a) I am not at the liberty to change the script which starts the app on the linux box. Therefore, I cannot pass any of the "jmxremote" parameters to the jvm.
b) It is very possible that the remote port ( com.sun.management.jmxremote.port = xxxx ) I specify is not open and I cannot modify the script to try another open port. I must do it automatically.
I tried to get around these restrictions by writing a class with would set all the required jmxremote params as well as find a "free" port.
public class JmxRemoteConnectionHelper{
#Override
public void init( ) throws Exception{
InetAddress address = InetAddress.getLocalHost();
String ipAddress = address.getHostAddress();
String hostname = address.getHostName();
String port = String.valueOf( getFreePort( ) );
System.setProperty("java.rmi.server.hostname", ipAddress );
System.setProperty("com.sun.management.jmxremote", "true" );
System.setProperty("com.sun.management.jmxremote.authenticate", "false" );
System.setProperty("com.sun.management.jmxremote.ssl", "false" );
System.setProperty("com.sun.management.jmxremote.port", port );
}
private final int getFreePort( ){
**//seedPort is passed in the constructor**
int freePort = seedPort;
ServerSocket sSocket = null;
for( int i=ZERO; i<PORT_SCAN_COUNTER; i++ ){
try{
freePort = freePort + i;
sSocket = new ServerSocket( freePort );
//FOUND a free port.
break;
}catch( Exception e ){
//Log
}finally{
if( sSocket != null ){
try{
sSocket.close();
sSocket = null;
}catch(Exception e ){
//Log
}
}
}
}
return freePort;
}
}
As shown below, I, then initialize it via spring.
<bean id="JmxRemoteConnection" class="JmxRemoteConnectionHelper" init-method="init" />
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean" depends-on="JmxRemoteConnection" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false" >
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
<property name="server" ref="mbeanServer"/>
</bean>
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy" lazy-init="true">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
To test, I start the app on my windows machine. It starts up correctly. However, when I bring up JConsole on the same box and try to connect via "remote process" (ip:port), I get a "connection refused" message at the bottom.
My suspicion is that the JMX agent is not seeing any of the remote system properties that I am setting.
I am using JDK 1.6.
Since you are already using Spring I think you should see if using a ConnectorServerFactoryBean can do what you are looking to do. I've never had to start a remote JMX server but it looks like that's what that object can do for you.
See the answers to this for enabling jmx within the process:
Is it possible to enable remote jmx monitoring programmatically?
To find a free port simply wrap LocateRegistry.createRegistry() in a loop which retries with a new port number until it succeeds.
Of course you'll have to communicate the final port number to whatever needs to connect. Alternatively running jstatd on the host should make it discoverable

General JDBC Setup

So I have a MySQL database set up on a Debian server and it works fine from a phpMyAdmin client. I'm currently working on a project to write a Java server that would be able to use the MySQL database that is already on this server through a JDBC connection. I've looked at many tutorials and documentations but all of them seem to just explain how to do client-side code, but I have yet to figure out how to even successfully open a JDBC connection to the server. As far as I am concerned, I believe that program has the drivers properly set up because it's not crashing anymore (I simply direct the Java Build Path of my program to the Connector/J provided by MySQL). As far as my program goes, this is what it looks like...
import java.sql.*;
public class JDBCTest {
public static void main(String[] args) {
System.out.println("Started!");
try {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
System.out.println("Driver registered. Connecting...");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/", "root", "password");
System.out.println("Connected!");
conn.close();
} catch (SQLException e) {
System.out.println("Error!");
e.printStackTrace();
}
}
}
This is what's printed...
Started!
Driver registered. Connecting...
It's as if the DriverManager.getConnection(String) just freezes there. I'm sure this is a problem with the server because when I intentionally misspell localhost, or an IP address, the program crashes within 20 seconds. This just hangs there forever.
Sorry about this wall of text, but my final question is if anyone has any information what I should do or install on the server to get this to work? Thank you so much!
Try following:
public class MySqlDemo {
public static void main(String [] args) {
java.sql.Connection conn = null;
System.out.println("SQL Test");
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = java.sql.DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?user=root&password=");
}
catch (Exception e) {
System.out.println(e);
System.exit(0);
}
System.out.println("Connection established");
}
You have to provide the name of the Schema to which you are connecting. Usually, the port is also added.
This is a sample connection string:
jdbc:mysql://repos.insttech.washington.edu:3306/johndoe?user=johndoe&password=jddb
3306 is the port and the first instance of johndoe is the name of the Schema. The second instance of johndoe is the username.
It could be that the Connector/J library is trying to use a named pipe to connect to the MySQL server rather than using TCP/IP and for some reason the named pipe isn't available. Try specifying a port number.
You may also want to try turning on some logging in Connector/J's configuration as described here.
Try putting port number and schema there
Try logging into database using some SQL client, may be SQL console
Try other drivers, may be some newer or perhaps older

Categories

Resources