I think this is a bug.
I'm using latest MySQL JDBC library.
I have multiple threads. Each thread execute a query and for each row add a batch to a prepared statement.
Sometimes the instruction "stmt.setLong(i, aLong)" launch a NullPointerException.
stmt,i and aLong are not null.
PreparedStatement stmt = db.prepareStatement("myinsert");
while (rs.next()) {
long aLong = rs.getLong(1);
...
stmt.setLong(1,aLong);
stmt.addBatch();
}
Here is the exception:
java.lang.NullPointerException
at com.mysql.jdbc.ConnectionImpl.getServerCharacterEncoding(ConnectionImpl.java:3124)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3729)
at com.mysql.jdbc.PreparedStatement.setLong(PreparedStatement.java:3751)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:127)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:127)
at com.mypackage.MyClass$MyThread.run(MyClass.java:117)
If I launch only one thread, it works.
The exception also occurs without apache dbcp2 library.
I'm going crazy!
I solved the problem removing these lines of codes before creation of the ResultSet
Statement stmt = Database.getDatabase().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
From MySQL documentation here.
The combination of a forward-only, read-only result set, with a fetch size of Integer.MIN_VALUE serves as a signal to the driver to stream result sets row-by-row. After this, any result sets created with the statement will be retrieved row-by-row.
Related
When I run the code in non-batch mode it works:
PreparedStatement preparedStatement = connection.prepareStatement(
"DELETE FROM myTable WHERE id=58");
preparedStatement.execute();
However as soon as I try to run it in batch mode:
PreparedStatement preparedStatement = connection.prepareStatement(
"DELETE FROM myTable WHERE id=58");
preparedStatement.executeBatch();
It will no longer delete the entry from the table. All my INSERTS work perfectly well with executeBatch, in fact everything so far except the DELETE command. It doesn't come back with any kind of error, it just seems to ignore the command and skip over it. And if I inspect the number of columns affected by looking at the int[] returned it's empty (int[].length = 0).
Update: I don't believe it's a permission issue because the user account has full root privileges and access to all commands. And if it was a permission issue then it shouldn't work in non-batch mode.
The issue was that for the delete SQL statement for whatever reason I forgot to add the following line:
preparedStatement.addBatch();
Omitting this line means the PreparedStatement was never added to the batch and hence never executed. There are of course no warnings or errors because the SQL statement is never executed, it's just omitted. As there were other SQL batch PreparedStatement in the batch there was no need for an empty batch exception to be thrown (some drivers will throw an exception but this is not guaranteed so don't rely on it).
Therefore the correct code would be:
PreparedStatement preparedStatement = connection.prepareStatement(
"DELETE FROM myTable WHERE id=58");
preparedStatement.addBatch();
preparedStatement.executeBatch();
Now as pointed in a comment you would normally not want to execute a single SQL command with batching, the reason this was done was to isolate the issue to the specific SQL command.
The logs stop at logger.warn("Start: preparedStatement.executeQuery()"); and hangs indefinitely. No exception is thrown in the logs. The query doesn't show up in SHOW FULL PROCESSLIST under the info column which would mean the query isn't even executed. I'm able to execute the query in commandline and it takes less than a second to bring back all rows. SHOW OPEN TABLES WHERE IN_USE <> 0 returns an empty set so no table is locked. Using JDK 1.8, MySQL 1.6, InnoDB.
*Edit: This is running on AWS and I noticed a large spike in CPU utilization before the hang.
public void setup(StringBuilder sql, String[] args, RowMapper<I> rowMapper) throws SQLException{
this.rowMapper = rowMapper;
//Create prepared statement
connection.setAutoCommit(false);
logger.warn("Start: Connection.preparedStatement");
preparedStatement = connection.prepareStatement(sql.toString(),ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
logger.warn("End: Connection.preparedStatement");
preparedStatement.setFetchSize(fetchSize);
//Setting SQL arguments
int i = 1;
for(String var: args){
preparedStatement.setString(i++, var);
}
logger.warn("Start: preparedStatement.executeQuery()");
resultSet = preparedStatement.executeQuery();
logger.warn("End: preparedStatement.executeQuery()");
}
Solved it. There was a synchronized lock in StatementImpl.class Version 1.5 around line 1373 that was waiting for a lock to come off which is why the thread was hanging. I have multiple result sets open at the same time so I ended up giving each result set it's own connection and setting the fetch size to Integer.MIN_VALUE and the application isn't stuck now.
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 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 want to INSERT several rows using a PreparedStatement:
ps = con.prepareStatement(query,PreparedStatement.RETURN_GENERATED_KEYS);
for(Element e:listOfElements){
ps.setString(1,this.col_val_1);
ps.setString(2,this.col_val_2);
ps.setInt(3,this.col_val_3);
ps.addBatch();
}
ps.executeBatch();
ResultSet rs = ps.getGeneratedKeys();
At this point, whent I expect to get the PK's generated for each INSERT, I get this SQLServerException:
com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.
I expected to get a ResultSet with one row for each insert performed, so I could get each PK generated.
Am I expecting wrong? Am I doing something wrong? Can it be done in a different way using batch execution?
Support for getGeneratedKeys() on batch execution is implementation defined according to the JDBC spec. Most likely the SQL Server driver does not support it for batch execution.
I tried to look for an explicit statement on the Microsoft site, but couldn't find it. This old (2007) forum post on MSDN does state that it isn't supported: http://social.msdn.microsoft.com/Forums/en-US/sqldataaccess/thread/6cbf5eea-e5b9-4519-8e86-f4b65ce3f8e1