different results if PreparedStatement is used as resource in try block - java

Some behaviour I don't understand.
I have a running script like:
ResultSet res = null;
String cmd = new String("SELECT value FROM " +pDS.getValueTableName() + " WHERE itemID=? and propertyID=? ORDER BY checkpointID DESC");
PreparedStatement pstmt= dbconn.prepareStatement(cmd) ;
pstmt.setLong(1,itemID);
pstmt.setLong(2,pDS.getPropertyID());
try {
res = pstmt.executeQuery();
}
catch(Exception e)
{
throw(e);
}
if (!res.next())
{
// other code
}
Here i get the expected values res.next()=true.
No exception is thrown.
I wanted to refactor the code, and use the Autoclose funtionalty of the try block, like:
ResultSet res = null;
String cmd = new String("SELECT value FROM " +pDS.getValueTableName() + " WHERE itemID=? and propertyID=? ORDER BY checkpointID DESC");
try (PreparedStatement pstmt= dbconn.prepareStatement(cmd) ){
pstmt.setLong(1,itemID);
pstmt.setLong(2,pDS.getPropertyID());
res = pstmt.executeQuery();
}
catch(Exception e)
{
LOGGER.error("Error at getLatestPropertyResultSet",e);
throw(e);
}
if (!res.next())
{
// other code
}
However now res.next()=false. The resultset itselve is intialized res!=null.
Why did this modification change the behaviour of the script?

Without seeing where you call res.next() I can only assume that the try-with-resource is doing exactly as advertised and closing the prepared statement once you leave the try block and thus the result is "closed" with it.
update: based on your edit my suspicions are confirmed. You need to move any work related to the resource inside the try block.

Related

How can you get a JTextField to work in a SQLite Select statement?

I am working on a program which will when finished allow the end user to keep track of there sound packs in a database through SQLite. The newest problem I am running into is that I can not get the Select statement to take a JTextField input. The reason that I want to do this is that I already have the text fields linked through the insert method. I have tried switching the variable types in the readAllData method and I am not entirely sure what other way to fix it.
The fields are as follows
PackId
PackName
VendorName
PackValue
what I want to happen is when I hit the Update button I want the data in the database to print out to the console (for now) and I am also going to be adding a select specified records method as well.
Here is the code I do apologize in advance this is a very long project:
public void readAllData() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:sqlite:packsver3.db");
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT * FROM packs";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()) {
String PackId = PackId.getText();
String PackName = PackName.getText();
String VendorName = VendorName.getTextField();
String PackValue = rs.getTextField;
System.out.println("All Packs\n");
System.out.println("PackId: " +PackId);
System.out.println("PackName: " +PackName);
System.out.println("VendorName: " +VendorName);
System.out.println("PackValue: " +PackValue+"\n\n");
}
} catch (SQLException e) {
System.out.println(e.toString());
}finally {
try {
assert rs != null;
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
System.out.println(e.toString());
}
Console Output

ResultSet is Closed

Following is my Table Definition:
create Table alarms(
alarmId int primary key identity(1,1),
alarmDate varchar(50) not null,
alarmText varchar(50) not null,
alarmStatus varchar(10) Check (alarmStatus in(-1, 0, 1)) Default 0
);
Secondly here are some of my methods i'm using:
public void restartDatabase(){
try{
Class.forName(Settings.getDatabaseDriver());
connection = DriverManager.getConnection( Settings.getJdbcUrl() );
statement = connection.createStatement();
}
catch(Exception e){
e.printStackTrace();
}
}
public ResultSet executeQuery(String query){
ResultSet result = null;
try {
result = statement.executeQuery(query);
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
public void closeDatabase() {
try {
if ((statement != null) && (connection != null)) {
statement.close();
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
What i want to do is to get all the alarmId's from the table where date is equal to the given date and then against each alarmId i want to update its status to given status:
public static void updateAlarmStatus(int status) {
ResultSet rs = null;
database.restartDatabase();
try {
rs = database
.executeQuery("Select alarmId from alarms where alarmDate = '"
+ Alarm.getFormattedDateTime(DateFormat.FULL,
DateFormat.SHORT) + "'");
while (rs.next()) {
database.executeUpdate("update alarms set alarmStatus = '"+status+"' where alarmId = '"+rs.getString("alarmId")+"'");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
database.closeDatabase();
}
}
But it generates the Error that Result Set is Closed.
I Goggled it and came to know that a result set automatically closes when we try to execute another query inside it
and it needs to restart the connection.
i tried calling restartDatabase() method that is creating new connection but still getting the same error.
I'm guessing executeUpdate uses the same instance variable for its Statement as the query uses. When you create a new Statement and assign it to the variable, nothing is referring to the old one, so it gets cut loose and becomes subject to garbage-collection. During garbage collection the statement's finalizer is invoked, closing it. Closing the statement makes the ResultSet it created close as well.
You shouldn't be sharing these Statement variables between different queries and updates. The statement should be a local variable and not a member of an object instance.
Also, result Sets should always be local variables, they shouldn't be passed outside the method where they're created. The resultSet is a reference to a cursor, it doesn't actually hold any data. Always have your code read from the resultSet and populate some data structure with the results, then return the data structure.
You can also select and change all alarmIds at once:
rs = database.
executeQuery("Select group_concat(distinct alarmId) as alarmIds from alarms group by alarmDate having alarmDate = '"
+ Alarm.getFormattedDateTime(DateFormat.FULL,
DateFormat.SHORT) + "'");
while (rs.next()) { // there will be only one result
database.executeUpdate("update alarms set alarmStatus = '"+status+"' where alarmId in ("+rs.getString("alarmIds")+")");
}

Java. Statement execution in cycle

I try to execute INSERT query in cycle:
String selectTableSQL = "SELECT * "
+ "FROM testTable";
ResultSet rs = stmt.executeQuery(selectTableSQL);
while (rs.next()) {
String rangeName = rs.getString("RANGENAME");
insertTableSQL = "INSERT INTO testTable2 "
+ "VALUES ('" + rangeName + "')";
try {
stmt.executeUpdate(insertTableSQL);
} catch (SQLException e) {
// do nothing
}
But after one iteration this cycle breaks. If I don't execute INSERT query and print rangeName to screen everything works perfectly (there are a lot of values, not only one). So the problem is in statement execution. How can I solve it?
Thank you very much!
Of course it does: you're using the same stmt
Create a new stmt2 variable and use it inside loop without destroying the previous one.
First: Never do so
} catch (SQLException e) {
// do nothing
}
Add a e.printStackTrace() to the catch block.
I think you get an exception when you do so. You may need a second statement variable.

java.sql.SQLException: Exhausted Resultset error

I'm facing the problem with this exception java.sql.SQLException: Exhausted Resultset in following code. I'm sure my query returns only one value. Even If I don't use rs.next(); it throws the error java.sql.SQLException: ResultSet.next was not called. Could you please help?
FYI, I'm using the another result set in main where this menthod from another class is called. will it affect?
Thanks
public static String getdispname(Connection conn, String resname)
throws SQLException, Exception {
//String resname = "";
String returnValue = "";
String querystring = "";
//Query to select the displayname from resid
querystring += "select distinct display_name";
querystring += " from cust_rally_team_member";
querystring += " where display_name like '%"+ resid +"%'";
// Create select statement
Statement stmt = conn.createStatement();
try {
// Execute statement
ResultSet rs = stmt.executeQuery(querystring);
if (rs!= null) {
while (rs.next()) {
returnValue = rs.getString("display_name");
} catch (SQLException ex) {
throw new SQLException(ex);
} catch (Exception ex) {
throw new Exception(ex);
}
// Close statement
finally {
stmt.close();
}
return returnValue;
Try as
if (rs! = null) {
while (rs.next()) {
returnValue = rs.getString("display_name");
}
......
Try:
returnValue = rs.next() ? rs.getString("display_name") : null;
You don't need to check if the rs is null. It won't be - assuming the executeQuery() returned rather than raising an exception. (Though the returned result set might have 0 rows).
You also don't need to loop over the result set, assuming you really know that you expect back a single row. (Though, given the query, that seems unlikely.)
use by your modification like below
if (rs != null && rs.first()) {
do {
returnValue = rs.getString(("display_name");
} while (rs.next());
}
I am using Oracle 10g database , i found same error "java.sql.SQLException: Exhausted Resultset error". I just grant permission in database and solved my probblem.
SQL> grant insert,update,delete on "table-name" to "database_name";

Executing two Java PreparedStatements with one connection - style choice

Okay, I've realized that I really have asked way too many questions without contributing back to the community, but I want your opinions on this. Say if I have
private void closeAll(ResultSet rs, PreparedStatement ps, Connection con) {
if (rs != null)
try {
rs.close();
} catch (SQLException e) {
}
if (ps != null)
try {
ps.close();
} catch (SQLException e) {
}
if (con != null)
try {
con.close();
} catch (SQLException e) {
}
}
and I wanted to do several operations on my MySQL database using a single connection. Is it better to write
Connection con = ...;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = con.prepareStatement(...);
rs = ps.executeQuery();
if (rs.next()) ...;
} catch (SQLException e) {
System.err.println("Error: " + e);
} finally {
closeAll(rs, ps, null);
}
try {
ps = con.prepareStatement(...);
rs = ps.executeQuery();
if (rs.next()) ...;
} catch (SQLException e) {
System.err.println("Error: " + e);
} finally {
closeAll(rs, ps, con);
}
or
Connection con = ...;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = con.prepareStatement(...);
rs = ps.executeQuery();
if (rs.next()) ...;
rs.close();
ps.close();
ps = con.prepareStatement(...);
rs = ps.executeQuery();
if (rs.next()) ...;
} catch (SQLException e) {
System.err.println("Error: " + e);
} finally {
closeAll(rs, ps, con);
}
I consider better to mean either safer, clearer, more concise, or more robust. I'm not sure whether the latter will always close whichever prepared statements and result sets are open whenever it encounters an exception, while I believe it does look more concise. But the former looks nicer since it's more consistent, yet it puts more overhead since it uses more try finally blocks.
I realize that Java 7's automatic resource management part of Project Coin will force me to lean to the former since the resources used in the header are implicitly final in the body. However, I have quite some time before I have to worry about revising my code to adapt it to ARM and be able to remove the boilerplate code, so the question still stands: of the above two styles, which would be better practice? If they both do the expected behaviors, will the latter give me a noticeable performance boost that would excuse the "uglier" style?
It seems to me this is a case of personal preference. In my time I've written code that resembles both blocks. As regards performance I don't think there would be a particularly noticeable difference, only performance tests would tell.
It might be a case that the millisecond or so difference that one version delivers isn't half as important as the ten minutes or so that another person reading your code six months after you've written it would spend asking why.
My personal preference would be the second. You say you're holding a connection open to the database. With the first block of code if you get an exception thrown, that would be handled but then you'd drop down to the second try/catch and try again. You might not want that if the first one failed. With the second, an exception would cause you come out of the code and then close your connection.
I've programmed mainly in C#. It was about eight years ago when I last did any Java. But I think there is and have been plenty of C# programmers who've pondered this. I have at any rate.
If you look at it, you'll see that logic is somewhat different - first version will execute second query even if first query handling will fail. Second version will only proceed to executing second query, if handling first query+results will succeed.
The 2nd one is the way to go. The first one may fail to close the connection when an exception occurs in first try-block. When you just do printing to stderr in the catch-block then not, but you won't do that. Or should the 2nd statement be executed without respect to success/failure of first one?
I realise that this post is old, but if you are lucky enough to be running in a Java7 environment- I would suggest using the try-with-resource.
It will handle the connection closing for you- as the new versions of the class implement the Closable interface.
public static void viewTable(Connection con) throws SQLException {
String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + ", " + supplierID + ", " +
price + ", " + sales + ", " + total);
}
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
}

Categories

Resources