Executing two Java PreparedStatements with one connection - style choice - java

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

Related

JDBC ResultSet closed in Java after several iterations

I am having a problem with a ResultSet being closed. What confuses me is that it works for a portion of the data and then closes. At first I thought it might be because of connection timeout but that doesn't seem the case.
This portion of the program pertains to comparing an .xlsx workbook to an already present SQL database and for lack of a better term merges/updates it.
First, in my CompareDatabase class I am calling a search function that searches an SQLite database for a specific string every 6 iterations.
int columnCount = 6;
dataPoint = dataPoint.replaceAll("Detail", "");
String[] temp = dataPoint.trim().split("\\s+");
System.out.println(Arrays.toString(temp));
for (String tempDataPoint : temp) {
if ( columnCount == 6) {
System.out.println(search(tempDataPoint, connection));
}
columnCount = 0;
} else {
columnCount++;
}
}
This search function (also in the CompareDatabase class is then supposed to search for the value and return a String (was originally a Boolean but I wanted to see the output).
private String search (String searchValue, Connection connection) throws SQLException {
PreparedStatement pStatement = null;
pStatement = connection.prepareStatement("SELECT * FROM lotdatabase where (Vehicle) = (?)");
pStatement.setString(1, searchValue);
try (ResultSet resultSet = pStatement.executeQuery()){
return resultSet.getString(1);
}finally {
close(pStatement);
}
}
At the end you can see that the PreparedStatement is closed. The ResultSet should also be closed automatically (I read somewhere) but JDBC could possibly be being unreliable.
The Connection however is still open as it will be searching some 200+ strings and opening and closing that many times did not seem like a good idea.
These functions are called by my main class here:
One is commented out since it will error out because of primary key violation.
public static void main(String[] args) {
SQLDatabase sqlDatabase = new SQLDatabase();
//sqlDatabase.convertToSQL("Database1.xlsx");
sqlDatabase.compare("Database2.xlsx");
}
I have a suspicion that I am going about a bunch of this wrong (on the aspect of managing connections an such) and I would appreciate a reference to where I can learn to do it properly.
Also, being that PreparedStatement can only handle one ResultSet I don't see that being my issue since I close it every iteration in the for loop.
If more code or explanation is required please let me know and I will do my best to assist.
Thank you for taking the time to read this.
So after a bit more Googling and sleeping on it here is what worked for me.
The search function in compareDatabase changed to this:
private Boolean search (String searchValue, Connection connection) {
PreparedStatement ps = null;
try {
ps = connection.prepareStatement("SELECT * FROM lotdatabase where " +
"(Vehicle) = (?)");
ps.setString(1, searchValue);
ResultSet resultSet = ps.executeQuery();
//The following if statement checks if the ResultSet is empty.
if (!resultSet.next()){
resultSet.close();
ps.close();
return false;
}else{
resultSet.close();
ps.close();
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
And in the other function within compareDatabase I call the search function like this:
if (search(tempDataPoint, connection)) {
System.out.println("MATCH FOUND: " + tempDataPoint);
}else {
System.out.println("NOT FOUND: " + tempDataPoint);
}
This allows me to check the ResultSet and also be sure that it is closed.

different results if PreparedStatement is used as resource in try block

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.

How to write a MySQL query in Java with user parameters with dates [duplicate]

This question already has answers here:
Passing parameters to a JDBC PreparedStatement
(5 answers)
Closed 9 years ago.
First of all guys thanks for the previous help and advice. I am only learning databases and MySQL, so please bear with me while I ask so major newbie type questions.
I'm entering 2 parameters, one is a string and the other is a date. I then want to then output of a another value. The string is straight forward but I'm unable to compare the dates properly. If the dates and the strings match then that is the record I'm looking for
Here is a copy of the table
private String agentDetail = "CREATE TABLE AgentDetail ("
+ "idNo INT(64) NOT NULL AUTO_INCREMENT,"
+ "initials VARCHAR(2),"
+ "agentDate DATE,"
+ "agentCount INT(64), "
+ "PRIMARY KEY(idNo))";
The problem is that it always brings back all the dates, both the correct and incorrect results
and here is the code that I am currently using
protected void getAgentIdNo (Connection con, PreparedStatement preStatement,
ResultSet result, String initials, Date myDate) {
try {
preStatement = con.prepareStatement("SELECT * FROM AGENTDETAIL");
result = preStatement.executeQuery();
while (result.next()) {
if (result.getString("initials").equals(initials)){
if (myDate.compareTo(result.getDate("agentDate")) == 0){
System.out.println("The date and initials matched !!");
System.out.println("The id no is " + result.getint("idNo");
}
}
}
}
catch (SQLException ex) {
System.out.println("An error occured when reading from the data base");
ex.printStackTrace();
}
}
I also know that this code is far from perfect so feel to suggest a more professional looking code.
Thanks in advance for any all help and support.
That was a bad idea. This is the way to do it:
preStatement = con.prepareStatement("SELECT * FROM AGENTDETAIL WHERE initials = ? AND angetDate = ?");
preStatment.setSring(1, initials);
preStatment.setDate(2, new java.sql.Date(date.getTime()));
Instead of make the filter programaticaly, i recommend (in this case to make a SQL query).
You can do something like:
protected void getAgentIdNo (Connection con, PreparedStatement preStatement,
ResultSet result, String initials, Date myDate) {
try {
preStatement = con.prepareStatement("SELECT * FROM AGENTDETAIL as ag WHERE ag.initial = ? AND date = ?");
preStatment.setSring(1,initials);
preStatment.setString(2,date);
result = preStatement.executeQuery();
while (result.next()) {
System.out.println("The date and initials matched !!");
System.out.println("The id no is " + result.getint("idNo");
}
}
}
catch (SQLException ex) {
System.out.println("An error occured when reading from the data base");
ex.printStackTrace();
}
}
Att: For more detail consult this link.
Hope it Helps ^^
First of all,
I would like to thank those who have read, reviewed and submitted a poor hacks work.
There was 2 different schools of thought that emerged and I of course tried both. It is great to try different methods.
I have found that for the code that I'm currently writing while I search for a job, this works very cleanly. However the other responses has also led me to investigate other opportunities that was given.
The segment is part of bigger system which I'm writing to increase my portfolio of work, What I am doing is using Java to create a visual interface, which will only assign one idNo to the user per day. The user may then come along and in another segment of code be given the opportunity to manually enter a customer number or alternatively generate one. This is where the idNo and agentCount numbers come in. By the way I found that command line code programming is way easier. :-)
protected void getAgentIdNo (Connection con, PreparedStatement preStatement, ResultSet result, AgentDetail ageDet) {
try {
preStatement = con.prepareStatement("SELECT * FROM AGENTDETAIL as ag WHERE ag.initials = ? AND ag.agentDate = ?");
preStatement.setString(1,ageDet.getInitials());
preStatement.setDate(2,ageDet.getMyDate());
result = preStatement.executeQuery();
while (result.next()) {
ageDet.setAgeIdNo(result.getInt("idNo"));
ageDet.setAgeCount(result.getInt("agentCount"));
}
}
catch (SQLException ex) {
System.out.println("An error occurred when reading from the data base");
ex.printStackTrace();
}
}
Thank you again Guys

Java, code works, but exception is still thrown

I am creating a simple registration frame that adds records onto a database. It gives me an error message every time it runs the SQL query that adds records in the database, however it still adds them, but because of that my programs gets to a standstill, instead of opening another window.
here's that part of the code:
regButton.addActionListener(new ActionListener() {
#Override public void actionPerformed( ActionEvent e ) {
//Execute when button is pressed
if( uNameField.getText().equals("")
|| new String(newPassField.getPassword()).equals("")
|| new String(repeatPassField.getPassword()).equals("") ) {
errorLabel.setForeground(Color.red);
errorLabel.setText("Some fields are left blank");
}
else if( new String(newPassField.getPassword()).equals(
new String(repeatPassField.getPassword()))){
Statement stmt;
ResultSet res;
try
{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
String sql;
sql = "INSERT INTO Employees VALUES ('" +username +"','" +password +"');";
stmt = con.createStatement();
res = stmt.executeQuery(sql);
System.out.println("Added to database!");
con.close();
}
catch(SQLException exe) {
System.out.println("Error creating or running statement: " + e.toString());
try {
con.close();
}
catch(Exception eex){}
}
}
else {
errorLabel.setForeground(Color.red);
errorLabel.setText("Password missmatch");
}
}
Every time it registers a new employee (user) it displays this "Error creating or running statement: ..... " although, I can find the newly added employees in the employee list.
What may be causing this problem?
Before we get to your specific problem, some general advice:
Connection con = ...
try {
// your stuff
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The way you are doing it now not only swallows the exception, but also avoids printing its stacktrace. And close must be performend once and only once, regardless of the exception.
If you are on Java 7, this would be much easier:
try (Connetion con = ...) {
// stuff to do
}
catch (Exception e) {
e.printStackTrace();
}
The closing in a finally is now done automatically.
Specifically about your exception, you execute an INSERT by calling executeQuery. This method sends the statement to the DB, which properly executes it, but its response back to the JDBC is not a ResultSet. This is where it blows up, after the record is already inserted. Since you are in autocommit mode, there is no transaction to roll back. Lesson: always use transactions.
You need to use executeUpdate for SQL INSERTs
int rowCount = stmt.executeUpdate(sql);
I hate seeing code written this way. You didn't ask about this, and my comment won't solve your problem, but I think it needs to be said.
You're creating a maintenance nightmare for yourself by putting persistence code in a Swing Listener method.
A better idea is to think about objects in a way that gives them a single responsibility.
Take your persistence code and move it into a separate class that you can develop and test on its own. Once it's working, give a reference to the class that needs it.
Your code will be more modular, easier to test, more reusable, and less of a nightmare to understand.
Uncle Bob Martin has a succinct mneumonic for this and other ideas worth remembering: SOLID.
why dont you try PreparedStatement
try{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
PreparedStatement pstmt = con.prepareStatement("insert into Employees values(?,?)");
pstmt.setString(1,username);
pstmt.setString(2,password);
if(!pstmt.execute())
{
//means your code worked correctly
System.out.println("Inserted successfully");
}
else
{
System.out.println("Unsuccessfull");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}

Why rs.next() don't go to another record

If I remove beforeFirst() my function does only first record in ResultSet and go to end. If I use beforeFirst() I get an error ResultSet IS_TYPE_FORWARD_ONLY.
try {
ResultSet rs = stat.executeQuery("select _id, godziny_id from tblZmiany where harmonogram_id = " + h_id + " order by pracownik_id, Dzien");
rs.beforeFirst();
while (rs.next()) {
if (stat.executeUpdate("insert into tblWykonanie (Zmiana_id, Godziny_id) values ('" + rs.getLong(1) + "', " + rs.getInt(2) + ");") < 1) {
// Jeśli insert nie wstawił kolejnego rekordu
error_code = "Wystąpił problem podczas zatwierdzania harmonogramu.";
return false;
}
}
} catch (SQLException e) {
e.printStackTrace();
System.out.println(e.getMessage());
return false;
} catch (Exception e) {
error_code = e.getMessage();
return false;
}
return true;
You're using the same Statement object for both the SELECT and the INSERT. From the Javadoc:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
To fix the problem, use a separate Statement object for the executeUpdate() call.
Also, I strongly advise you to change the code to use PreparedStatement with bound arguments (represented by ?). Building SQL statements bit by bit as you're doing right now could open up security vulnerabilities.
Your code has a major security flaw. You are vulnerable to SQL injection. Never, ever, ever, ever, ever, ever, ever, use string concatenation with SQL statements; use PreparedStatements instead!
harmonogram_id = " + h_id + " order by pracownik_id,
Take a look here to see how your application could be easily owned with simple tricks:
http://en.wikipedia.org/wiki/SQL_injection
To answer your question though, it depends on your database. You have to set a property during the connection creation:
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE),
ResultSet.HOLD_CURSORS_OVER_COMMIT);
From:
http://docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/resultset.html#1012735

Categories

Resources