I have create a java software which make use of sqlite database. The whole database works smoothly however after some time of running the application I am reveiving the following message (from a try catch block):
java.sql.SQLException: [SQLITE_BUSY] The database file is locked (database is locked)
I ve solved my problems by closing the software every time the exception rising. However is there a way to close my database instead so as not to close the software every time?
I ve got plenty of queries however my prob arises always in a specific point:
try {
String query = "select * from StudentsSession where userId=? and course=? and level=?";
PreparedStatement pst = connectionUsers.prepareStatement(query);
pst.setString(1, saveUser.getText());
pst.setString(2, textSubjectQTest);
st.setString(3, showCurrentLevelLabel.getText());
ResultSet rs = pst.executeQuery();
while (rs.next()) {
count = count + 1;
}
pst.close();
rs.close();
} catch (Exception a) {
System.out.println(a);
}
try {
String countS, tmpS;
countS = String.valueOf(count);
sessionId.setText(countS);
long unixTime = System.currentTimeMillis() / 1000L;
tmpS = String.valueOf(unixTime);
date.setText(tmpS);
course.setText(textSubjectQTest);
String query = "insert into StudentsSession (userId,date,course,level,trial,score) values (?,?,?,?,?,-1)";
PreparedStatement pst = connectionUsers.prepareStatement(query);
pst.setString(1, saveUser.getText());
pst.setString(2, tmpS);
pst.setString(3, textSubjectQTest);
pst.setString(4, showCurrentLevelLabel.getText());
pst.setString(5, countS);
pst.executeUpdate();
pst.close();
} catch (Exception a) {
System.out.println(a);
System.exit(0);
}
String file1 = "";
ResultSet ts4;
try {
sessionId3 = "";
String query3 = "select * from studentssession where userid = ? and course = ? and level = ?";
PreparedStatement pst__1 = connectionUsers.prepareStatement(query3);
pst__1.setString(1, saveUser.getText());
pst__1.setString(2, textSubjectQTest);
pst__1.setString(3, showCurrentLevelLabel.getText());
ts4 = pst__1.executeQuery();
while (ts4.next()) {
sessionId3 = ts4.getString("sessionId");
}
pst__1.close();
ts4.close();
obj = new CaptureVideoFromWebCamera();
file1 = "videos/" + userTextFieldS.getText();
file1 = file1 + "_" + sessionId3;
file1 = file1 + ".wmv";
obj.start(file1);
} catch (Exception e4) {
e4.getCause();
}
Sometimes this code rise the exception.
Every time you open a connection with the SQLite database, make sure to close the database connection after you process the results or etc. if you already have an open connection to the database and if you try to get the connection again and try some Update or Insert queries, the system will not give the permission and will raise an error.
Your try catch are wrong, you try to close the ResultSet and Statemnt in the try block instead of a finally block. This could lead to leaks.
You should do it like this, in the finally.
PreparedStatement pst = null;
ResultSet rs = null;
try {
pst = connectionUsers.prepareStatement(query);
...
rs = pst.executeQuery();
...
} catch (Exception a) {
a.printStackTrace();
} finally {
if(rs != null){
try{
rs.close();
} catch(Exception e){
e.printStackTrace();
}
}
if(pst != null){
try{
pst.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
Or you could look to the Try-with-resource.
This could be a reason.
Sorta duplicate of existing question, but this is a good starting point. Because SQLite is just a library that reads and writes to a file on the file system, not a full SQL database, you should really only have one connection open to it at a time. Otherwise it is pretty easy to get into a race condition.
For local testing, it should be fine, but for a system of any complexity expecting multiple users, you should be using something like Postgre or MySQL.
Related
I'm tying to get an image from MySQL database and show in a JLabel, but when I execute the query and try to get the bytes from the ResultSet it returns an empty array.
I tested the connection, and it is working, tested the query and its also working.
try {
conn = getConnection();
pst = conn.prepareStatement("select * from imagem where serial_imagem = 123658");
rs = pst.executeQuery()
if (rs.next()) {
image = rs.getBytes("img_imagem");
}
}catch (Exception e) {
e.printStackTrace();
}
The code does not close and thus leaks resources. The somewhat ugly Try-With-Resources syntax ensures closing connection, statement and result set, even on returning/exception.
One could make explicit with Optional whether the image was found in the table or not.
Optional.of also guarantees that the field in the database must not contain an SQL NULL value.
Optional<byte[]> loadImageFromDatabase(String imageM) throws SQLException {
String sql = "select img_imagem from imagem where serial_imagem = ?";
try (Connection conn = getConnection();
PreparedStatement pst = conn.prepareStatement(sql)) {
pst.setString(1, imageM);
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
return Optional.of(rs.getBytes(1)); // ofNullable
} else {
return Optional.empty();
}
}
}
}
Usage:
try {
Optional<byte[]> img = loadImageFromDatabase(jtextField1.getText().trim());
img.ifPresent(image -> {
...
});
} catch (SQLException e) {
There is still to remark that I personally do not often use ResultSet.getBytes, but rather getInputStream. Depends on the image size and creation code.
in my small test program I have some SQL Queries. The first SELECT * FROM kilometer; works properly and returns all the columns in the table. So in Java embedded, ResultSet rs = stmt.executeQuery("SELECT * FROM kilometer;"); returns an ResultSet which is not empty.
Now I wanted to get only the rows within a specific date. But my embedded query ResultSet rs = stmt.executeQuery("SELECT * FROM kilometer WHERE datum BETWEEN '2016-01-01' AND '2016-12-31';"); returns an empty ResultSet. But I've tested it online and it worked properly. Where is my mistake? I've consulted already some pages like this, but I can't find the mistake.
I am using SQLite 3.15.1 and Java SE 8.
Full java code:
public ArrayList<Strecke> getErgebnisse(final String startzeitpunkt, final String zielzeitpunkt) {
ArrayList<Strecke> strecken = new ArrayList<>();
try {
try {
if (connection != null) {
}
connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
if (!connection.isClosed())
} catch (SQLException e) {
throw new RuntimeException(e);
}
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM kilometer WHERE datum BETWEEN '2016-01-01' AND '2016-12-31';");
while (rs.next()) {
strecken.add(new Strecke(Instant.ofEpochMilli(rs.getDate("datum").getTime()).atZone(ZoneId.systemDefault()).toLocalDate(), rs.getString("startort"), rs.getString("zielort"), rs.getDouble("kilometer")));
}
rs.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return strecken;
}
First of all I would recommend that you use prepared statements while executing your queries instead of passing the query directly as a string......secondly I believe the problem here is that you are passing the date as a string in quotes and not a date.....I think that is the issue here. You would need to use sqllites datetime functions for this....
I have below table structure
id msg keyword
-----------------
1 abc ?
2 xyz ?
The above is just an example; however my real table looks like that only. Based on the value of msg field, I need to call an API that would calculate the keywords from the msg and then update the particular record. How can I get the record and update as well, at the same time using Java PreparedStatement?
Also since my database is very large, what would be the efficient way to do it? Below is the code snippet :
public void updateColumns() {
try {
PreparedStatement stmt = null;
ResultSet resultSet = null;
String query = "select * from '" + Constants.tableName + "'";
// How to uypdate the record here by calling my custom API that reads the msg and returns the keywords in the message??
stmt = conn.prepareStatement(query);
stmt.execute();
stmt.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The idiomatic JDBC solution would be to generate a batch update :
String select = "SELECT id, msg FROM my_table";
String update = "UPDATE my_table SET keyword = ? WHERE id = ?";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(select);
PreparedStatement ps = conn.prepareStatement(update);) {
while (rs.next()) {
ps.setInt(1, rs.getInt(1));
ps.setString(2, MyAPI.calculateKeyword(rs.getString(2));
ps.addBatch();
}
ps.executeBatch();
}
Of course, if you table is very large, you may which to consider every X rows.
Trying to use prepareStatement on a query from an XML file:
<sql><![CDATA[
select MY_COLUMN from MY_TABLE where OTHER_COLUMN = ?
]]>
</sql>
But I get this exception:
com.ibm.db2.jcc.am.SqlException: [jcc][t4][10234][10927][3.59.81] SQL passed with no tokens. ERRORCODE=-4462, SQLSTATE=null
at com.ibm.db2.jcc.am.dd.a(dd.java:660)
at com.ibm.db2.jcc.am.dd.a(dd.java:60)
at com.ibm.db2.jcc.am.dd.a(dd.java:120)
at com.ibm.db2.jcc.am.jb.v(jb.java:7334)
at com.ibm.db2.jcc.am.jb.a(jb.java:2124)
at com.ibm.db2.jcc.am.jb.prepareStatement(jb.java:754)
I read that this is because the SQL is not in a single line. Is that the cause?
I also read that in IBM Portal, you have to change db2_zos.DbDriverType from 2 to 4. But I think it's irrelevant to me as I don't use IBM Portal.
Nothing else useful turned up from Google. I would love to know the real cause of the error, and to find an easier fix than forcing all SQL to single line.
Code:
ArrayList arrList = new ArrayList();
String sSQL = queryManager.getSQL("QRY001");
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConnection(); //a connection pool wrapper for java.sql.DriverManager.getConnection(...)
ps = conn.prepareStatement(sSQL); // **** EXCEPTION OCCURS HERE
ps.setInt(1, Integer.parseInt(otherColumn));
rs = ps.executeQuery();
while (rs.next())
{
arrList.add(rs.getString(1));
}
} catch (Exception e) {
e.printStackTrace();
throw new OEException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
releaseConnection(conn);
} catch (Exception e) {
throw new CustomException(e);
}
}
return arrList;
Because the SQL execution has comments;
Please refer to the official documentation
https://www.ibm.com/support/pages/apar/PH14323
Also try writing it like this
<sql>
select MY_COLUMN from MY_TABLE where OTHER_COLUMN = ?
</sql>
I have this method to load the objects, however when I am running the sql code it is giving me a Syntax error.
public void loadObjects() {
Statement s = setConnection();
// Add Administrators
try {
ResultSet r = s.executeQuery("SELECT * FROM Administrator;");
while (r.next()) {
Administrator getUser = new Administrator();
getUser.ID = r.getString(2);
ResultSet r2 = s.executeQuery("SELECT * FROM Userx WHERE ID= {" + getUser.ID + "};");
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
I have tried inserting the curly braces as stated in other questions, but I am either doing it wrong or it doesn't work.
This method should be able to load all administrators but I believe it is only inserting half of the ID.
The ID that it gets, consists of numbers and char; example "26315G"
the Error -
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '26315'.
Edit -
private java.sql.Connection setConnection(){
java.sql.Connection con = null;
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://" + host + ";DatabaseName=" + database + ";integratedSecurity=true;";
con = DriverManager.getConnection(url, username, password);
} catch(Exception e) {
System.out.println(e);
}
return con;
}
public void loadObjects() {
java.sql.Connection con = setConnection();
// Add Administrators
try {
PreparedStatement sql = con.prepareStatement("SELECT * FROM Administrator");
ResultSet rs = sql.executeQuery();
while (rs.next()) {
Administrator getUser = new Administrator();
getUser.ID = rs.getString(2);
PreparedStatement sql2 = con.prepareStatement("SELECT * FROM Userx WHERE ID=?");
sql2.setString(1, getUser.ID);
ResultSet r2 = sql2.executeQuery();
getUser.name = r2.getString(2);
getUser.surname = r2.getString(3);
getUser.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(getUser);
}
} catch (Exception e) {
System.out.println(e);
}
}
Actually it is not the way to do that in JDBC. That way, even if you sort your syntax error, your code is prone to sql injection attacks.
The right way would be:
// Let's say your user id is an integer
PreparedStatement stmt = connection.prepareStatement("select * from userx where id=?");
stmt.setInt(1, getUser.ID);
ResultSet rs = stmt.executeQuery();
This way you are guarded against any attempt to inject SQL in your application request parameters
First of all: if you use concurrently result-sets, you must use separate statements for each one of them (you can not share Statement s between two r and r2). And more, you lack r2.next() before reading from it.
On the other hand: it would be much more effective to use PreparedStatement in the loop that to rewrite the query all the time.
So I'd go for something like this:
public void loadObjects() {
try (
Statement st = getConnection().createStatement();
//- As you read (later) only id, then why to use '*' in this query? It only takes up resources.
ResultSet rs = st.executeQuery("SELECT id FROM Administrator");
PreparedStatement ps = getConnection().prepareStatement("SELECT * FROM Userx WHERE ID = ?");
ResultSet r2 = null;
) {
while (rs.next()) {
Administrator user = new Administrator();
user.ID = rs.getString("id");
ps.setInt(1, user.ID);
r2 = ps.executeQuery();
if (r2.next()) {
user.name = r2.getString(2);
user.surname = r2.getString(3);
user.PIN = r2.getLong(4);
JBDeveloping.users.administrators.add(user);
}
else {
System.out.println("User with ID=" + user.ID + " was not found.");
}
}
}
catch (Exception x) {
x.printStacktrace();
}
}
Please note use of Java7 auto-close feature (you didn't close resources in you code). And last note: until you are not separating statements in your queries, as to JDBC documentation, you should not place ';' at the end of statements (in all cases you shouldn't place ';' as the last character in you query string).
You should not use {} and you should not append parameters into a SQL query like this.
Remove the curly braces and use PreparedStatement instead.
see http://www.unixwiz.net/techtips/sql-injection.html