What is the difference between statement.executeQuery and statement.getResultSet(). I believe both will return ResultSet for a select statement but are there any specific criteria when we should use which of them.
In general you should use executeQuery if you know you are executing a select statement. The getResultSet() method by itself does not execute the statement.
The getResultSet is intended to be used in combination with execute. The execute methods are intended for use with unknown statement types, or statements that can produce multiple results (that is 0 or more update counts or result sets).
So in short: you should normally use executeQuery.
A simple example when you should use execute if the code doesn't know what query it is going to execute (an update, a query, or something more complex), for example when executing user provided queries.
Another example are SQL Server stored procedures, which can return multiple update counts and result sets.
A generic way of processing a result of execute is:
boolean isResultSet = statement.execute(sql);
while (true) {
if (isResultSet) {
try (ResultSet rs = statement.getResultSet()) {
// do something with result set
}
} else {
int updateCount = statement.getUpdateCount();
if (updateCount == -1) {
// -1 signals no more results
break;
}
// do something with update count
}
// move to next result
isResultSet = statement.getMoreResults();
}
This ensures that all* results get processed.
*: This example ignores exception results for systems (like SQL Server) that allow multiple exceptions to be interleaved with result sets and update counts, see How to get *everything* back from a stored procedure using JDBC for a more thorough example
Check out the JavaDoc for these methods. getResultSet can return null but executeQuery never return null.
There are also more constraints. For example executeQuery cannot be called on a PreparedStatement or CallableStatement.
Related
I am trying to insert into a db that I have, and I'd like to do so through parameters. I am connecting to a postgres db using java.
I can connect to the db just fine. I know that because I have various operations that I am using that are already working were I can see, and update existing rows in my db. I am having trouble with INSERT.
I have the following:
private String _update_rentals = "INSERT into rentals (cid, mid) values (?,?)";
private PreparedStatement _update_rentals_statement;
private String _update_movie_status = "UPDATE Movie SET checkedout = true WHERE mid = ?";
private PreparedStatement _update_movie_status_statement;
And I initialize them:
_update_movie_status_statement = _customer_db.prepareStatement(_update_movie_status);
_update_rentals_statement = _customer_db.prepareStatement(_update_rentals);
And
while (movieAvail.next()){
System.out.println(movieAvail.getBoolean(1));
if (movieAvail.getBoolean(1) == false){
//Do chekcout
_update_rentals_statement.clearParameters();
_update_rentals_statement.setInt(1, cid);
_update_rentals_statement.setInt(2, mid);
_update_rentals_statement.executeQuery();
_update_movie_status_statement.clearParameters();
_update_movie_status_statement.setInt(1, mid);
_update_movie_status_statement.executeQuery();
System.out.println("Enjoy your movie!");
}
}
I am getting an error with both of the executeQuery() calls. For some reason I am getting the following error with both:
Exception in thread "main" org.postgresql.util.PSQLException: No results were returned by the query.
I looked at other posts, and I believed that I was following syntax for both insert/ update correctly, so maybe I am overlooking some aspect of this.
This is all part of a larger code base, so I did not want to include the methods these pieces of code are in. But these are the isolated instances which play a part with this code.
In general, when you execute a query, you are willing to retrieve some kind of information from the database. This is usually the case when you are executing SELECT queries. However, with INSERT and UPDATE statements, you are not querying the database, you are simply executing an update or inserting new rows. In the documentation of PreparedStatement you can see in which cases an exception is being thrown when you try to call executeQuery:
Throws: SQLException - if a database access error occurs; this method
is called on a closed PreparedStatement or the SQL statement does not
return a ResultSet object
So in your case the problem is that your statements do not return a ResultSet. You should use execute or executeUpdate instead. The former simply executes the update, while the latter does the same, but also returns the number of affected rows.
I think the main issue is that you are calling executeQuery(), which expects a result to be returned, but Insert/Update are not queries and don't return a result. Try just calling execute().
I have an PL/SQL block like this:
BEGIN
FOR i IN 1..100
LOOP
UPDATE rptbody
SET comments = 'abcs';
WHERE (rptno> 100 and rptno < 200) and ROWNUM<2;
COMMIT;
END LOOP;
END;
This block needs to be executed using Oracle JDBC. I have tried the following methods:
Tried to execute this using Statement object. Since this is a block, an exception was raised saying that this is not an sql statement
This can be split up into sql statements, but I have 100s of such blocks which would be cumbersome for the code and thought of leaving this to the sqlplus.
Tried with CallableStatement which did not work as well.
Any solutions would be helpful.
This has nothing to do with how you run it. The PL/SQL syntax is invalid. You have a ; after the update clause right before the WHERE clause:
BEGIN
FOR i IN 1..100
LOOP
UPDATE rptbody
SET comments = 'abcs' --<<< no semicolon here!!
WHERE (rptno> 100 and rptno < 200) and ROWNUM<2;
COMMIT;
END LOOP;
END;
The above code can be run like this:
String sql = "... the PL/SQL block ...";
Statement stmt = connection.createStatement();
stmt.execute(sql);
Check out some code samples to use CallableStatement and PreparedStatement on Github
Tried to execute this using Statement object. Since this is a block, an exception was raised saying that this is not an sql statement
Since you were trying to execute a plsql block, you should not use Statement object.
From https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html:
The object used for executing a static SQL statement and returning the results it produces.
This is the way you need to execute a block:
CallableStatement anonBlock = null // Note that CallableStatement is an interface
String anonBlockString = '' //Generally multi line
// Set in and out parameters as needed by your anonBlockString
anonBlock.registerOutParameter( <number> , <type> )
...
// executeUpdate() is inherited from PreparedStatement and can be used for executing DML statements (update, insert, delete)
anonBlock.executeUpdate();
To access out parameters:
anonBlock.getString(<number which you have assigned in registerOutParameter() calls);
For complete example: (https://download.oracle.com/otn_hosted_doc/timesten/1121/quickstart/sample_code/jdbc/plsqlJDBC.java)
This can be split up into sql statements, but I have 100s of such blocks which would be cumbersome for the code and thought of leaving this to the sqlplus.
Prefer to use stored procedures instead of anonymous blocks. Since stored procedures are stored in a compiled and optimized format, they have a performance boost compared to anonymous ones
Tried with CallableStatement which did not work as well:
What was the code, error/stack?
I am using MySQL Database. The following piece creates a record and gets the id from the created record:
insertStmt = connection
.prepareStatement("INSERT INTO bugs (summary, status, report_date) VALUES (?, ?, ? )");
//...
insertStmt.executeUpdate();
idQuery = connection.prepareStatement("SELECT LAST_INSERT_ID()");
rs = idQuery.executeQuery();
if (rs != null) {
rs.next();
return new Long(rs.getLong(1)).toString();
}
Now, if two threads execute this and their execution is interleaved, say, the first thread inserts the record followed by the insertion by the second thread, after which the first thread calls last_insert_id() which will be incorrect for this thread as the second thread has already inserted a record.
This might be overcome using synchronization, however. Is there a way we can execute the two statements in a single database call?
LAST_INSERT_ID works per-connection, and as your question states you can have a race condition if two statements in two threads use the same connection.
You have two ways around this:
1: Use a separate connection per thread (not easy, but this is really the best option for scaling and sense; use connection pooling)
2: Use the form of executeUpdate that records the auto-generated key in the same API call, allowing you to read it back later using getGeneratedKeys so that you don't have to use LAST_INSERT_ID in a second query, so avoiding the race condition. There's a similar form of prepareStatement that you can use in prepared statements.
Option 2 is probably what you want in the short term. The link in option 2 goes straight to that API. This link is a MySQL article outlining how to use it.
According to https://dev.mysql.com/doc/refman/5.7/en/connector-j-reference-configuration-properties.html, you should be able to add ?allowMultiQueries=true to your JDBC connection string. Then you would be able to pass multiple statements, separated by semicolons, in Statement#execute(String sql) calls.
Edit: or, use a stored procedure that does what you want. Or, as you said, synchronize the Java code.
You can try using a Multiquery, combined the Insert and the Select Last_INSERT_ID() in the same string.
1) prepare the connection for using the multiquery:
"jdbc:mysql://"+host+"/"+database+"?allowMultiQueries=true"
2) Combine The Insert Query with the Select:
multiQuerySqlString="INSERT INTO bugs (summary, status, report_date) VALUES (1, 2, 3 ); SELECT LAST_INSERT_ID()"
3) esecute the query and expecting multiple result sets:
boolean isResultSet = statement.execute();
ResultSet res = statement.getResultSet();
if isResultSet = statement.getMoreResults();
// Second ReulstSet object
res = cs.getResultSet();
I hope it works
If you have to do this all on a single connection you can ask the driver to return the generated ID:
insertStmt = connection.prepareStatement("...",PreparedStatement.RETURN_GENERATED_KEYS );
insertStmt.executeUpdate();
ResultSet rs = insertStatement.getGeneratedKeys();
Long id = null;
if (rs != null)
{
rs.next();
id = rs.getLong(1);
}
connection.commit();
return id;
Depending on the driver you might need a different prepareStatement() call that takes the column names as the second parameter:
insertStmt = connection.prepareStatement("INSERT ", new String[] {"ID"});
But even in with the above code you should be doing the concurrent inserts on different physical connections to be able to properly control your transactions.
I have come across a strange behavior while executing a SELECT query using Statement#executeUpdate() by mistake. While the Javadoc clearly states that executeUpdate() throws SQLException if the given SQL statement produces a ResultSet object. But when I'm executing SELECT * from TABLE_NAME, I don't get any exception. Instead I'm getting an return value which is same as the no. of rows selected, if no. is less than or equal to 10. If the no. is more than 10, the return value is always 10.
Connection conn;
Statement stmt;
try {
conn = getConnection();
stmt = conn.createStatement();
int count = stmt.executeUpdate("SELECT * from TABLE_NAME");
log.info("row count: " + count);
} catch (SQLException e) {
log.error(e);
// handle exception
} finally {
DbUtils.closeQuietly(stmt);
DbUtils.closeQuietly(conn);
}
I am using Oracle 10g.
Am I missing something here or is it up to the drivers to define their own behavior?
This behaviour is definetely contradicts Statement.executeUpdate API. What's interesting,
java.sql.Driver.jdbcCompliant API says "A driver may only report true here if it passes the JDBC compliance tests". I tested oracle.jdbc.OracleDriver.jdbcCompliant - it returns true. I also tested com.mysql.jdbc.Driver.jdbcCompliant - it returns false. But in the same situation as you describe it throws
Exception in thread "main" java.sql.SQLException: Can not issue SELECT via executeUpdate().
It seems that JDBC drivers are unpredictable.
According to the specifications Statement.executeUpdate() method returns the row count for SQL Data Manipulation Language (DML).
UPD: I attempted to make an assumption about the returned result (which is always <=10). It seems, that the oracle statement's implementation returns here a number of a such called premature batch count (according to the decompiled sources OraclePreparedStatement class). This is somehow linked to the update statements. May be this value equals 10 by default.
UPD-2: According to this: Performance Extensions: The premature batch flush count is summed to the return value of the next executeUpdate() or sendBatch() method.
The query you are using doesn't produce a ResultSet but affects Rows obviously. That's why you don't get an SQLException but a count of the no of rows affected. The mystery is why it doesn't go beyond 10. May it is Oracle JDBC Driver Implementation Specific.
Your sql query is to retrieve all rows from table_name. So, you can use execute() method instead of executeUpdate() method. Because later method generally use when your task is related database manipulating language like update query.
use
int count = stmt.executeQuery("SELECT * from TABLE_NAME");
instead of
int count = stmt.executeUpdate("SELECT * from TABLE_NAME");
for getting total no. of rows.
I have a prepared statement call in java that calls a procedure that commits or rolls back a sybase transaction. Is there anyway I can check from my java calls the result of that transaction, ie. success for commit or failure for rollback?
Alternatively, I want to check that the procedure completed without errors - whats the best way of doing that?
Thanks
If the rollback or commit happens within the stored procedure, then the only way to know the success is to have the stored procedure return its success status. Then, Java will have access to this result.
A stored procedure should return some kind of status or error code.
Put that in an OUT parameter and read that from the proc.
//Calling a stored procedure which takes in 2 parameters for addition
/*
--EXECUTE ADDITION 10,25,NULL
ALTER PROCEDURE ADDITION
#A INT
, #B INT
, #C INT OUT
AS
SELECT #C = #A + #B
*/
CallableStatement cs2 = con.prepareCall("{call ADDITION(?,?,?)}");
cs2.registerOutParameter(3,java.sql.Types.INTEGER);
cs2.setInt(1,10);
cs2.setInt(2,25);
cs2.execute();
int res = cs2.getInt(3);
System.out.println(res);
I think you're using the wrong approach. The client (the JAVA code in this case) should be committing or rolling back, not the sybase stored procedure. I assume here that by "calling a procedure" you mean a stored procedure that commits or rolls back.
If you use the approach I just mentioned, then you can put everything in a try/catch block and handle the commit/rollback accordingly.
try {
PreparedStatement ps = create prepared statement;
ps.execute();
// nothing went wrong, commit
} catch (SqlException e) {
// something wen't wrong, rollback
}
If by "calling a procedure" you mean just another JAVA method, then the I don't know why you would have a separate method to do a commit or rollback, you can handle it all in the try/catch block as shown above.