How to refresh table after con.commit() in java? - java

I am creating a new register in table MY_TABLE using java and then, I am doing a query to obtain the max(id) of that table. However, Java is obtaining the previous one. I mean:
mybean.store(con)
con.commit();
pstm = con.prepareStatement("SELECT MAX (ID) FROM MY_TABLE");
rs = pstm.executeQuery();
while (rs.next()){
id = rs.getString("ID");
System.out.println("id: " +id);
}
Before con.commit(); the table has the max(ID)=3
After com.commit() the table has the max(ID)=4
But I obtain MAX(ID)=3
Can somebody help me to solve this?

You're doing it; if this is returning the wrong result either your DB doesn't contain what you think it contains, or your DB engine is broken (MySQL is often broken, possibly that's the problem. The fix is to not use mysql), or your code is broken. Your snippet contains an error (no semicolon after the first line), so this isn't a straight paste but a modification; generally you should paste precisely the code that is exhibiting the behaviour you don't understand, because if you edit it or try to simplify it without running the simplification, you may have accidentally removed the very thing that would explain what you're observing.
More generally, if all you want is the ID generated for an auto-increment column, this isn't how you do it. You can use statement's .getGeneratedKeys() method to get at these; you may have to pass in Statement.RETURN_GENERATED_KEYS as part of your executeUpdate call.

You do not need a PreparedStatement if you do not have a parametrized query. I would use Statement in this case.
You do not need while (rs.next()) as your query will return a single value. I would use if (rs.next()).
Your query does not have a field called ID and therefore rs.getString("ID") will throw SQLException. You should use rs.getString(1) or use an alias (e.g. maxId in the example shown below) in the query. Also, you should use getInt instead of getString.
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT MAX(ID) AS maxId FROM MY_TABLE");
int id = Integer.MIN_VALUE;
if (rs.next()) {
id = rs.getInt(1);
//id = rs.getInt("maxId");
}
System.out.println(id);

Related

Getting SQL Exception when trying to get the last auto-incremented value

I've been trying everything, nothing is working, I'm new to mysql and databases and I want to get the last auto-incremented id (primary key) (user_id) from a table, from java. So this: SELECT MAX(user_id) FROM database_user; works fine in mysql, I got that, but why can't I get the same thing from java??
PreparedStatement st = connection.prepareStatement("SELECT MAX(user_id) from database_user");
st.executeUpdate();
ResultSet rs = st.executeQuery();
int uid = rs.getInt(1);
System.out.println(uid);
This gives me java.sql.SQLException: (conn=213) the given SQL statement produces an unexpected ResultSet object
This isn't the only thing I tried, it's just the last one so far. If anyone could just shed some light I would greatly appreaciate it.
You are missing rs.next(); between executing the query and fetching from the result set. This is needed, to move the result set to the first row.
You also shouldn't have st.executeUpdate(). Just executing once is enough.

Java PreparedStatement SQL syntax error [duplicate]

This question already has answers here:
Java PreparedStatement complaining about SQL syntax on execute()
(6 answers)
Closed 6 years ago.
This is a really weird error that only started appearing today. When I use a prepared statement with ? for parameters, I get an error, but when I use it without parameters, it works just fine.
Here is the error-causing code:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM ?");
prep.setString(1, table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This produces the following error:
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''files'' at line 1
Also, changing it to the following works just fine:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM " + table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This doesn't seem to be making a whole lot of sense. Any ideas?
Tried it on another table and got more weired results.
This works and logs the admin in correctly:
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE " + column + " = '" + hashedPassword + "'";
PreparedStatement prepared = connection.prepareStatement(sql);
The following doesn't cause errors, but returns a message saying that the password entered is incorrect (it's correct - I double triple checked).
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE ? = ?";
PreparedStatement prepared = connection.prepareStatement(sql);
prepared.setString(1, column);
prepared.setString(2, hashedPassword);
Got it: use ? for values.
Also, the answer here helped.
Bind parameters cannot be used for identifiers in the SQL statement. Only values can supplied through bind placeholders.
This will work:
SELECT foo FROM bar WHERE id = ?
This will not work, because the table name is an identifier
SELECT foo FROM ? WHERE id = 2
You can't supply a column name, because column names are also identifiers.
A statement like this will run, but it may not do what you think it does.
SELECT ? AS foo FROM bar WHERE ? = 0
If we supply values of 'foo' for both placeholders, the query will actually be equivalent to a query containing two string literals:
SELECT 'foo' AS foo FROM bar WHERE 'foo' = 0
MySQL will run that statement, because it's a valid statement (if the table bar exists and we have privileges on it.) That query will return every row in bar (because the predicate in the WHERE clause evaluates to TRUE, independent of the contents of the table.. And we get returned the constant string foo.
It doesn't matter one whit that the string foo happens to match the name of column in our table.
This restriction has to do with how the SQL optimizer operates. We don't need to delve into all the details of the steps (briefly: parsing tokens, performing syntax check, performing semantics check, determining query plan, and then the actual execution of the query plan.)
So here's the short story: The values for bind parameters are supplied too late in that process. They are not supplied until that final step, the execution of the query plan.
The optimizer needs to know which tables and columns are being referenced at earlier stages... for the semantics check, and for developing a query plan. The tables and columns have to be identified to the optimizer. Bind placeholders are "unknowns" at the time the table names and column names are needed.
(That short story isn't entirely accurate; don't take all of that as gospel. But it does explain the reason that bind parameters can't be used for identifiers, like table names and column names.)
tl;dr
Given the particular statement you're running, the only value that can be passed in as a bind parameter would be the "hashedPassword" value. Everything else in that statement has to be in the SQL string.
For example, something like this would work:
String sqltext = "SELECT * FROM mytable WHERE mycolumn = ?";
PreparedStatement prepared = connection.prepareStatement(sqltext);
prepared.setString(1, hashedPassword);
To make other parts of the SQL statement "dynamic" (like the table name and column name) you'd have to handle that in the Java code (using string concatenation.) The contents of that string would need to end up like the contents of the sqltext string (in my example) when it's passed to the prepareStatement method.
The parameters of PreparedStatement should be applied only in parameters that can be used in conditional clauses. The table name is not the case here.
If you have a select where the table name can be applied in the conditional clause you can do it, otherwise you can not.

Getting Incorrect return in java accessing sql database

This is the code im using in java to query the database
connect = DriverManager.getConnection (url, "user", "pass");
state = connect.createStatement();
String meetID = "SELECT GamerTag FROM backup";
ResultSet rs = state.executeQuery(meetID);
while(rs.next()){
System.out.println(rs.toString());
}
Im not getting the values of the row in the database im getting this instead
com.mysql.jdbc.JDBC4ResultSet#108137c9
You're printing the result of the toString method of the Recordset object, which appears to print out the object's name and hashcode.
Instead, try to print the value of a column. Perhaps using getString:
System.out.println(rs.getString("GamerTag"));
The documentation for Java's recordset looks confusing, you might be better off searching for examples.
What do you expect rs.toString() should do it will just print the hash of the resultsetObject if you want to get the column values you should do this way
while(rs.next()){
System.out.println(rs.getString("yourFirstColumnName")+" "+
rs.getString("yourSecondColumnName")+" "+
rs.getString("yourThirdColumnName"));
}
Really you should use PreparedStatement. In your case though you are not using any parameterizedQuery but One of the major benefits of using PreparedStatement is better performance. PreparedStatement gets pre compiled.
In database and there access plan is also cached in database, which allows database to execute parametric query written using prepared statement much faster than normal query because it has less work to do. You should always try to use PreparedStatement.
So you can do something like this
String query = "SELECT GamerTag FROM backup"
PreparedStatement st =connect.prepareStatement("query");
ResultSet rs = st.executeQuery();

SQL Server deadlock when using PreparedStatements

I have a java servlet application and I'm using a prepared query to update a record in a SQL Server Database table.
Lets say I want to execute UPDATE MyTable SET name = 'test' WHERE id = '10'. (Yes, id is a varchar)
I used the following code to make this happen:
PreparedStatement pstmt = con.prepareStatement("UPDATE MyTable SET name = ? WHERE id = ?");
pstmt.setString(1, getName() );
pstmt.setString(2, getID() );
pstmt.executeUpdate();
I found out that while I was running a JMeter script to simulate 2 users, this statement causes a deadlock in my database.
I wanted to check what my values were in the SQL Profiler so I used the following code, so I could check the values.
String query = String.format("UPDATE MyTable SET name = '%s' WHERE id = '%s' ", getName(), getID() );
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.executeUpdate();
Suddenly my deadlock was gone! It's a shame the last approach is vulnerable to SQL injection.
Is there somebody who can tell me what is going on and/or how to fix it?
Ok I finally found the problem and solution to my problem.
It seemed that the combination of the jTDS JDBC driver with MSSQL was the 'problem'.
This article explained my situation exactly. And with the help of this FAQ I was able to set the datasource to the right configuration.
From what I understand:
If you have statement that uses a String-like index (Like in my situation), the table performs an index SCAN instead of an index SEEK. This causes the whole table to be locked and vulnerable to deadlocks.
I hope this will help other people too.

Using JDBC to read and update each row

I am able to read each line of a query fine, but I would also like to update a field as they are read.
The following code breaks when I add the two rs.update lines.
Connection con = DriverManager.getConnection(url, user, pass);
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE)
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
amount = rs.getInt("amount");
username = rs.getString("username");
rs.updateString("processed", "true");
rs.updateRow();
}
It would appear I've found my answer:
[SEVERE] com.mysql.jdbc.NotUpdatable: Result Set not updatable (referenced table has no primary keys).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.
It won't hurt to add primary keys to my database, probably the right way to do it anyway.
I added primary key to my database and it works beautifully.
Thanks!

Categories