getGeneratedKeys() after PreparedStatement.executeBatch() - java

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

Related

JDBC doesn't seem to want to call DELETE PreparedStatement when batched for MySQL

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.

neo4j insert using jdbc but cannot query immediately within the same connection

question background:
1.database is neo4j 2.3.1, driver using jdbc;
2.db connection initialized as a class member, default is auto-commit(not changed);
To avoid insert duplicates, i query before insert. after program stopped, found duplicates. why?
code:
String query = "CREATE (n:LABEL {name:'jack'})";
System.out.println(query);
Statement stmt = dbConnection.createStatement();
stmt.executeUpdate(query);
stmt.close();
Use MERGE + unique constraints instead
How do you "check"
You would have to check in the same tx and also take a write lock
after debugging i found that for neo4j-jdbc(v2.1.4), the default db connection transaction level is TRANSACTION_NONE, then i set it to TRANSACTION_READ_COMMITTED, above issue disappeared. so i think that TRANSACTION_READ_COMMITTED will force the previous insert committed, though this is not the recommended way. for isolation level refer to:Difference between read commit and repeatable read

NullPointerException while setting prepared statement parameters

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.

Why do I see NotUpdatable when I invoke ResultSet.refreshRow()?

When I invoke following rows:
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet resultSet = statement.executeQuery("select * from user");
resultSet.next();
resultSet.refreshRow();//exception throws here
I see following exception:
com.mysql.jdbc.NotUpdatable: Result Set not updatable.This result set
must come from a statement that was created with a result set type of
ResultSet.CONCUR_UPDATABLE, the query must select only one table, can
not use functions and must select all primary keys from that table.
See the JDBC 2.1 API Specification, section 5.6 for more details.This
result set must come from a statement that was created with a result
set type of ResultSet.CONCUR_UPDATABLE, the query must select only one
table, can not use functions and must select all primary keys from
that table. See the JDBC 2.1 API Specification, section 5.6 for more
details.
I wondered this exception because if read refreshRow method javadoc we can find following:
The refreshRow method provides a way for an application to explicitly
tell the JDBC driver to refetch a row(s) from the database
Thus following direction: database --> ResultSet
I have following understanding:
updatable is possibility to use following direction:
ResultSet --> database
Thus I don't understand cause of problem.
please clarify.
When you are using, ResultSet.CONCUR_READ_ONLY, you are getting an exception, that
com.mysql.jdbc.NotUpdatable: Result Set not updatable.This result set
must come from a statement that was created with a result set type of
ResultSet.CONCUR_UPDATABLE, the query must select only one table, can
not use functions and must select all primary keys from that table.
See the JDBC 2.1 API Specification, section 5.6 for more details.\
So, changing ResultSet.CONCUR_READ_ONLY to ResultSet.CONCUR_UPDATABLE, solved your problem. Correct?
Now, as I understand, you don't want to do that. Am I right? If yes, then I think you are confusing ResultSet with Database,
ResultSet.CONCUR_READ_ONLY, means read only ResultSet, not Database, similarly
ResultSet.CONCUR_UPDATABLE, means updatable ResultSet, not Database.
The method, resultSet.refreshRow(), suppose to update the resultSet, hence it rightly requires updatable ResultSet. I hope it's clear now.

How to search and insert a value using java code?

String link = "http://hosted.ap.org";
I want to find whether the given url is already existing in the SQL DB under the table name "urls". If the given url is not found in that table i need to insert it in to that table.
As I am a beginner in Java, I cannot really reach the exact code.
Please advise on this regard on how to search the url in the table.
I am done with the SQL Connection using the java code. Please advise me on the searching and inserting part alone as explained above.
PreparedStatement insert = connectin.preparedStateme("insert into urls(url) vlaues(?)");
PreparedStatement search = connectin.preparedStateme("select * from urls where url = ?");
search.setString(1, <your url value to search>);
ResultSet rs = search.executeQuery();
if (!rs.hasNext()) {
insert.setString(1, <your url value to insert>);
insert.executeUpdate();
}
//finally close your statements and connection
...
i assumed that you only have one field your table and field name is url. if you have more fields you need to add them in insert query.
You need to distinguish between two completely separate things: SQL (Structured Query Language) is the language which you use to communicate with the DB. JDBC (Java DataBase Connectivity) is a Java API which enables you to execute SQL language using Java code.
To get data from DB, you usually use the SQL SELECT statement. To insert data in a DB, you usually use the SQL INSERT INTO statement
To prepare a SQL statement in Java, you usually use Connection#prepareStatement(). To execute a SQL SELECT statement in Java, you should use PreparedStatement#executeQuery(). It returns a ResultSet with the query results. To execute a SQL INSERT statement in Java, you should use PreparedStatement#executeUpdate().
See also:
SQL tutorial
JDBC tutorial

Categories