Updating database after updating resultset - java

I have the below code to get data from a database and update it. How ever, result set is getting updated but, I don't see the changes in the database. Even after I say commit(), database is not getting updated. What am I missing here?
Connection connect = ConnectionManager.getInstance().getConnection();
Statement st = connect.createStatement();
st.execute("Select * from ...");
ResultSet rs = st.getResultSet();
ResultSetMetaData md = rs.getMetaData() ;
rs.absolute(1);
rs.updateObject("StepName","ABCD" );
connect.commit();
//connect.close();
EDIT:
Now, i have the below method, but I get the error as indicated.
rs.updateString("StepName", "ABCD");
rs.updateRow();
//rs.updateObject("StepName","ABCD" );
Error: com.jnetdirect.jsql.u: sp_cursor: The cursor identifier value provided (0) is not valid.
OK I have it working now. Below is the way I had to change.
Working solution:
Connection connect = ConnectionManager.getInstance().getConnection();
Statement st = connect.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
st.execute("Select * from ...");
ResultSet rs = st.getResultSet();
String queuename = "apples";
String updatedname = "bananas";
while(rs.next())
{
if(rs.getString(3).equals(queuename))
{
rs.updateString(3, updatedname );
System.out.println("updated: " + rs.getString(3));
rs.updateRow();
}else
{
System.out.println(rs.getRow() + ": " + rs.getString(3));
}
}
connect.commit();
rs.close();
connect.close();
}

If you look at the spec of updateObject :
Updates the designated column with an Object value. The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database.
rs.updateObject alone doesn't update the database. Try adding a call to rs.updateRow() after updateObject.

rs.absolute(1); might be not be moving the cursor. Try:
rs.next();
You can try a straight up SQL statement:
StringBuffer updates = new StringBuffer();
updates.append("UPDATE table_name ");
updates.append("SET StepName = ? );
updates.append("WHERE id = ?");
Statement updateStatement = connect.createStatement(updates.toString());
updateStatement.setString(1, "BlaBla");
updateStatement.setInt(2, 143);
updateStatement.executeUpdate();

When you make your call to createStatement you need to use the overload that allows you to specify an updatable resultset.
Here is an example if found: http://www.xyzws.com/Javafaq/how-to-use-updatable-resultset-in-jdbc/179
I think it's possible that not all driver\databases support this operation.

Related

java.sql.SQLException: Operation not allowed after ResultSet closed [help] [duplicate]

When I execute the following code, I get an exception. I think it is because I'm preparing in new statement with he same connection object. How should I rewrite this so that I can create a prepared statement AND get to use rs2? Do I have to create a new connection object even if the connection is to the same DB?
try
{
//Get some stuff
String name = "";
String sql = "SELECT `name` FROM `user` WHERE `id` = " + userId + " LIMIT 1;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
name = rs.getString("name");
}
String sql2 = "SELECT `id` FROM `profiles` WHERE `id` =" + profId + ";";
ResultSet rs2 = statement.executeQuery(sql2);
String updateSql = "INSERT INTO `blah`............";
PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql);
while(rs2.next())
{
int id = rs2.getInt("id");
int stuff = getStuff(id);
pst.setInt(1, stuff);
pst.addBatch();
}
pst.executeBatch();
}
catch (Exception e)
{
e.printStackTrace();
}
private int getStuff(int id)
{
try
{
String sql = "SELECT ......;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
return rs.getInt("something");
}
return -1;
}//code continues
The problem is with the way you fetch data in getStuff(). Each time you visit getStuff() you obtain a fresh ResultSet but you don't close it.
This violates the expectation of the Statement class (see here - http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html):
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
What makes things even worse is the rs from the calling code. It is also derived off-of the statement field but it is not closed.
Bottom line: you have several ResultSet pertaining to the same Statement object concurrently opened.
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.
I guess after while(rs2.next()) you are trying to access something from rs1. But it's already closed since you reexecuted statement to get rs2 from it. Since you didn't close it, I beleive it's used again below.

SQLServerException: A result set was generated for update

I'm trying to insert a new record into an MS SQL database, and I'm getting an exception I've never seen before. When I call executeUpdate the following exception is thrown:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
This is the Java code that produces the error:
// addComment method adds a new comment for a given requestId
public CommentBean addComment(CommentBean comment) {
PreparedStatement stmt = null;
INative nat = null;
Connection conn = null;
try {
nat = dbConn.retrieveNative();
conn = (Connection)nat.getNative("java.sql.Connection");
stmt = conn.prepareStatement(ADD_COMMENT);
stmt.setInt(1, comment.getRequestId());
stmt.setString(2, comment.getComment());
stmt.setString(3, new SimpleDateFormat("MM/dd/yyyy").format(comment.getDateCreated()));
stmt.setString(4, comment.getCreatedBy());
comment.setCommentId(stmt.executeUpdate()); // exception
} catch(Exception ex) {
System.err.println("ProjectRegistration::SQLDAO - addComment");
ex.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
} catch (Exception e) {}
}
return comment;
}// end addComment
Where ADD_COMMENT is defined as a String:
private static final String ADD_COMMENT = "INSERT INTO RequestComments OUTPUT INSERTED.commentId VALUES(?,?,?,?)";
For the sake of being thorough, the table is defined as:
CREATE TABLE RequestComments (
commentId int NOT NULL PRIMARY KEY IDENTITY(1,1),
requestId int FOREIGN KEY REFERENCES Requests(requestId),
comment varchar(400),
dateCreated date,
createdBy varchar(12)
);
I don't think I'm doing anything terribly complicated here, but I can't think of why I'm getting this exception. I have a method in the same class which does the exact same type of insertion (literally the same query with a different table name and number of values), and it has no issues. Does anyone have any ideas on how to resolve this issue?
This particular error can also be caused by an INSERT-trigger, which has a SELECT-statement as a part of the trigger code.
To test whether this is the case, you can try:
using executeQuery(), instead of executeUpdate() - and display the result.
executing the insert in tool like MySQL Workbench, SQL Server Management Studio, or whatever flavour of database design tools are available for your DBMS, to see whether a result is returned.
Related: sql server error "A result set was generated for update"
I'm hoping this may help others looking at the same error message, as it did for me. My solution was to live with a call to executeQuery(), although it only handles an underlying issue, instead of fixing it.
This instruction stmt.executeUpdate() is not returning the commentId, it returns a ResultSet which you could then get the commentId from. Something like this,
ResultSet rs = stmt.executeQuery(); // Not update, you're returning a ResultSet.
if (rs.next()) {
comment.setCommentId(rs.getInt(1));
}
you are using OUTPUT in your insert query i.e you will get a resultset after your query executes and to hold that you need an object of class ResultSet to hold that data
SqlServer : When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
Connection conn = DriverManager.getConnection(connectDB,user,pwd);
String sql = " set nocount off;INSERT INTO test (name) values (1)";
PreparedStatement prepareStatement = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
System.out.println(prepareStatement.executeUpdate());
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if(generatedKeys.next()){
System.out.println(generatedKeys.getString(1));
}
Related:
set-nocount-on-usage
I've had a similar problem where after a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}

Getting an Integer From MySQL Select Statement

I would like to get an integer saved in my MySql DB into an Integer in Java. I have a Table, that includes PlayerName and Level. I would like to get The Level (Integer) From a Specific Player. And then Add Integer "Value" to it. Then put it back in the DB. My Code up to now is:
public void addinputPData(String loc, int value, Player player, String playername){
//add input Player Data
try{
logm("Putting Kill Death Int Data into " +player.getName() + "'s Profile!");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/WebCom", "root", "MyPW");
int ovalue = -1;
Statement stmt = (Statement) con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT "+loc+" FROM PlayerData WHERE PlayerName='"+playername+"'");
if(rs.next()){
ovalue= rs.getInt(loc);
}
if(ovalue == -1){
logm("Error Occured");
}
int nvalue = value + ovalue;
String insert = "UPDATE PlayerData SET "+ loc + "='" + nvalue + "' WHERE PlayerName='" + playername + "'";
stmt.executeUpdate(insert);
con.close();
}catch(Exception e){
logm("Could Not Send Data To MYSQL DATABASE SERVER s: "+ e.getMessage());
}
}
I don't know why this won't work, Is there anything obvious that i am missing? Thank you in advance.
So first what you must understand is that when you won't use parametrized statements, there is big danger of SQL Injection. So your code is very dirty written.
So anyway, use PreparedStatement with parametrized SQL statements for much more better performace. Now rewrite your code like this:
final String SELECT_QUERY = "SELECT level FROM PlayerData WHERE PlayerName = ?";
final String UPDATE_QUERY = "UPDATE PlayerData SET level = ? WHERE PlayerName = ?";
public boolean dataMethod(String playerName) {
Connection con = null;
PreparedStatement ps = null;
PreparedStatement ps1 = null;
ResultSet rs = null;
int dataLevel = 0;
try {
// getConnection etc...
ps = con.prepareStatement(SELECT_QUERY);
ps.setString(1, playerName) // first param is order of ? param, starts with 1(not 0)
rs = ps.executeQuery();
while (rs.next()) {
dataLevel = rs.getInt();
}
if (dataLevel > 0) {
ps1 = con.prepareStatement(UPDATE_QUERY);
ps1.setInt(1, dataLevel);
ps1.setString(2, playerName);
ps1.executeUpdate();
}
return true;
}
catch (SQLExcetion ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally {
if (con != null) {
con.close();
}
}
}
Step by step, first init your statement, sets parameters if you have then when you use select, you will retrieve data in ResultSet that is table of data generated with query. imlicitly cursor in ResultSet is position before first row so you have to use next() method to go on current row and with the help of getter method you add data from ResultSet to your variable. Then you check if it's correct, if do, init second statement and execute it. And that's all.
But you should consider when you use more that 1 operation, sets autoCommit on false and all operations will do in one Transaction, because implicitly in JDBC is one operation = one transaction. And second, you should consider to use SQL stored procedures for add any data, update data or delete. It's more safer yet and less code. So let database working when it able to do it and also it's faster of course.
At the last, really you should think about this approach and makes your code more safer, faster and cleaner. Not have look on simplicity but on efficiency, compability and security.
More about SQL Injection
And when you decided right to use stored procedure, you can use it like this:
CREATE OR REPLACE PROCEDURE SOME_NAME(VARCHAR v_name PlayerData.name%type)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
// body
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
So now you have to create String for call procedure.
final String CALL_SOMENAME = "{call SOME_NAME(?)}";
Then intead of PreparedStatement you have to use CallableStatement that is interface used to execute SQL stored procedures.
cs.prepareCall(CALL_SOMENAME); // Creates a cs object for calling db stored procedures
cs.setString(1, playerName);
cs.execute();
I don't know why many people searching the easiest way to do something and don't look at performance and readability of code.
Regards
In the UPDATE statement, you're inserting the value for the "loc" column as a string (there are single quotes around the value). If the database column is an integer, then this could be causing a problem.
Tip: JDBC provides a class called PreparedStatement. This class allow you to build SQL queries safely. It makes sure that all user input is properly escaped in order to avoid security vulnerabilities.
PreparedStatement ps = con.prepareStatement("UPDATE PlayerData SET " + loc + " = ? WHERE PlayerName = ?");
ps.setInt(1, nvalue);
ps.setString(2, playername);
ps.execute();

Resultset closed exception

I am trying to retrieve results from a DB in a resultset. However i want to execute an update query for each entry in the resultset, but i get an exception.
this is my code
try {
Statement statement = sqlconnection.conn.createStatement();
query = "select * from reminders where year<= "+ syear +" and month<=" + smonth +" and date<"+ sday +" and reminded like 'false';";
rs= statement.executeQuery(query);
while (rs.next()){
id=rs.getInt("sno");
String reminder = rs.getString("remind");
JOptionPane.showMessageDialog(null, reminder);
statement.executeUpdate("update reminders set reminded='true' where sno="+id+";");
}
Can any1 show me a better way of doing this ?? I am pretty new to programming. Hence showing me how to it will be really helpful.
thanks
You're still looping over the results from statement when you're trying to perform an update with it. I'd try using a second Statement object for your updates.
Your ResultSet is not updatable.
Statement statement = sqlconnection.conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

How to get a value from the last inserted row? [duplicate]

This question already has answers here:
How to get the insert ID in JDBC?
(14 answers)
Closed 7 years ago.
Is there some way to get a value from the last inserted row?
I am inserting a row where the PK will automatically increase, and I would like to get this PK. Only the PK is guaranteed to be unique in the table.
I am using Java with a JDBC and PostgreSQL.
With PostgreSQL you can do it via the RETURNING keyword:
PostgresSQL - RETURNING
INSERT INTO mytable( field_1, field_2,... )
VALUES ( value_1, value_2 ) RETURNING anyfield
It will return the value of "anyfield". "anyfield" may be a sequence or not.
To use it with JDBC, do:
ResultSet rs = statement.executeQuery("INSERT ... RETURNING ID");
rs.next();
rs.getInt(1);
See the API docs for java.sql.Statement.
Basically, when you call executeUpdate() or executeQuery(), use the Statement.RETURN_GENERATED_KEYS constant. You can then call getGeneratedKeys to get the auto-generated keys of all rows created by that execution. (Assuming your JDBC driver provides it.)
It goes something along the lines of this:
Statement stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keyset = stmt.getGeneratedKeys();
If you're using JDBC 3.0, then you can get the value of the PK as soon as you inserted it.
Here's an article that talks about how : https://www.ibm.com/developerworks/java/library/j-jdbcnew/
Statement stmt = conn.createStatement();
// Obtain the generated key that results from the query.
stmt.executeUpdate("INSERT INTO authors " +
"(first_name, last_name) " +
"VALUES ('George', 'Orwell')",
Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
if ( rs.next() ) {
// Retrieve the auto generated key(s).
int key = rs.getInt(1);
}
Since PostgreSQL JDBC driver version 8.4-701 the PreparedStatement#getGeneratedKeys() is finally fully functional. We use it here almost one year in production to our full satisfaction.
In "plain JDBC" the PreparedStatement needs to be created as follows to make it to return the keys:
statement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
You can download the current JDBC driver version here (which is at the moment still 8.4-701).
The sequences in postgresql are transaction safe. So you can use the
currval(sequence)
Quote:
currval
Return the value most recently obtained by nextval for this sequence
in the current session. (An error is
reported if nextval has never been
called for this sequence in this
session.) Notice that because this is
returning a session-local value, it
gives a predictable answer even if
other sessions are executing nextval
meanwhile.
Here is how I solved it, based on the answers here:
Connection conn = ConnectToDB(); //ConnectToDB establishes a connection to the database.
String sql = "INSERT INTO \"TableName\"" +
"(\"Column1\", \"Column2\",\"Column3\",\"Column4\")" +
"VALUES ('value1',value2, 'value3', 'value4') RETURNING
\"TableName\".\"TableId\"";
PreparedStatement prpState = conn.prepareStatement(sql);
ResultSet rs = prpState.executeQuery();
if(rs.next()){
System.out.println(rs.getInt(1));
}
If you are using Statement, go for the following
//MY_NUMBER is the column name in the database
String generatedColumns[] = {"MY_NUMBER"};
Statement stmt = conn.createStatement();
//String sql holds the insert query
stmt.executeUpdate(sql, generatedColumns);
ResultSet rs = stmt.getGeneratedKeys();
// The generated id
if(rs.next())
long key = rs.getLong(1);
If you are using PreparedStatement, go for the following
String generatedColumns[] = {"MY_NUMBER"};
PreparedStatement pstmt = conn.prepareStatement(sql,generatedColumns);
pstmt.setString(1, "qwerty");
pstmt.execute();
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next())
long key = rs.getLong(1);
Use sequences in postgres for id columns:
INSERT mytable(myid) VALUES (nextval('MySequence'));
SELECT currval('MySequence');
currval will return the current value of the sequence in the same session.
(In MS SQL, you would use ##identity or SCOPE_IDENTITY())
PreparedStatement stmt = getConnection(PROJECTDB + 2)
.prepareStatement("INSERT INTO fonts (font_size) VALUES(?) RETURNING fonts.*");
stmt.setString(1, "986");
ResultSet res = stmt.executeQuery();
while (res.next()) {
System.out.println("Generated key: " + res.getLong(1));
System.out.println("Generated key: " + res.getInt(2));
System.out.println("Generated key: " + res.getInt(3));
}
stmt.close();
Don't use SELECT currval('MySequence') - the value gets incremented on inserts that fail.
For MyBatis 3.0.4 with Annotations and Postgresql driver 9.0-801.jdbc4 you define an interface method in your Mapper like
public interface ObjectiveMapper {
#Select("insert into objectives" +
" (code,title,description) values" +
" (#{code}, #{title}, #{description}) returning id")
int insert(Objective anObjective);
Note that #Select is used instead of #Insert.
for example:
Connection conn = null;
PreparedStatement sth = null;
ResultSet rs =null;
try {
conn = delegate.getConnection();
sth = conn.prepareStatement(INSERT_SQL);
sth.setString(1, pais.getNombre());
sth.executeUpdate();
rs=sth.getGeneratedKeys();
if(rs.next()){
Integer id = (Integer) rs.getInt(1);
pais.setId(id);
}
}
with ,Statement.RETURN_GENERATED_KEYS);" no found.
Use that simple code:
// Do your insert code
myDataBase.execSQL("INSERT INTO TABLE_NAME (FIELD_NAME1,FIELD_NAME2,...)VALUES (VALUE1,VALUE2,...)");
// Use the sqlite function "last_insert_rowid"
Cursor last_id_inserted = yourBD.rawQuery("SELECT last_insert_rowid()", null);
// Retrieve data from cursor.
last_id_inserted.moveToFirst(); // Don't forget that!
ultimo_id = last_id_inserted.getLong(0); // For Java, the result is returned on Long type (64)
If you are in a transaction you can use SELECT lastval() after an insert to get the last generated id.

Categories

Resources