PreparedStatement return getUpdateCount() = -1 - java

When we use the executeUpdate () method can not insert instructions to return ResultSet, such as a SELECT. I happen to have an update which to start a trigger, and the trigger have a command "Select * from table".
I could solve the problem by assigning this command to a variable as an example: "Select * from table " soon resultSet would be no problem for the JDBC executeUpdate.
The problem is that the system can work with triggers other integrated systems that have no domain and I can not change, so the option was to use the run command (), which as shown in the code image can I check if the return is a ResultSet ( return true). In the statement while discarding ResultSets generated in the trigger and getMoreResults returns me the number of rows affected by the Update, in the case of the frame in blue, using the statement returns the value 3, which is correct.
The problem is to use the PreparedStatement (red frame), where getUpdateCount is returning -1, but should return 3, which is the number of rows affected in the UPDATE.
Problem occurs in SQL Server 2012 database or 2008, it was not simulated with Oracle
Follows the code example with the existing trigger on the table that I'm doing update
I wonder if anyone knows why the return is different for getMoreResults.
Code Java
Trigger
public class TestarConexao {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
Connection conn = DriverManager.getConnection("jdbc:odbc:magnus;user=rh;password=rh;MARS_Connection=yes;", "rh", "rhk");
Statement stmt = conn.createStatement();
boolean is = stmt.execute("update Usu_teste set usu_codigo = 1 where usu_codigo = 1");
while (is) {
System.out.println("There is ResultSet: " + is);
is = stmt.getMoreResults();
}
System.out.println("UpdateCount with Statement: " + stmt.getUpdateCount());
PreparedStatement prepStmt = conn.prepareStatement("update Usu_teste set usu_codigo = 1 where usu_codigo = 1");
boolean isPrep = prepStmt.execute();
while (isPrep){
System.out.println("There is ResultSet: " + isPrep);
isPrep = prepStmt.getMoreResults();
}
System.out.println("UpdateCount with PreparedStatement: " +prepStmt.getUpdateCount());
}
}

Related

Unable to pass values to PreparedStatement - last fifth argument is skipped

I have the following problem. I have the method which use the query to check if there is any reservation for given place in time from Start to End to check if the user can book this place in given time then returns Ture of False. My problem is that every time my ResultSet is equal to null. I do debug step by step and all variables are properly passed. With the debugger, I found that after passing 4 arguments (2nd-time start date) the fifth is skipped and myRs value remains null. Also, the 4th argument after passing is underlined with the green line but no communication is displayed. I am using Netbeans. I have no idea whats going on. Here goes my DBUtil method code:
public boolean doesBookExist(int number, Date start, Date end) throws Exception {
boolean result = false;
Connection myConn = null;
PreparedStatement myStmt = null;
ResultSet myRs = null;
try {
// get a connection
myConn = dataSource.getConnection();
// create sql for validation
String sqlValidate = "SELECT * FROM `rezerwacje_miejsc`"
+ " WHERE `NR_MIEJSCA`=?"
+ " AND (`START` BETWEEN ? AND ?"
+ " OR KONIEC` BETWEEN ? AND ?)";
myStmt = myConn.prepareStatement(sqlValidate);
myStmt.setInt(1, number);
myStmt.setDate(2, new java.sql.Date(start.getTime()));
myStmt.setDate(3, new java.sql.Date(end.getTime()));
myStmt.setDate(4, new java.sql.Date(start.getTime()));
myStmt.setDate(5, new java.sql.Date(end.getTime()));
// execute query
myRs = myStmt.executeQuery(sqlValidate);
// check if there was a match
result = myRs.next();
return result;
} finally {
// close JDBC objects
close(myConn, myStmt, myRs);
}
This is incorrect:
myRs = myStmt.executeQuery(sqlValidate);
It should be just:
myRs = myStmt.executeQuery();
The version of executeQuery accepting a string is a holdover from Statement (API design problem). You want the one without parameters, which is provided by PreparedStatement.
There's also a typo in the query that I assume must just be in the question, not the real code: You have mis-matched backticks (you have one after KONIEC but not before it).

JDBC getDouble returns 0.0

I am new to Java and JDBC.
I am trying to get a double value from a database through JDBC and make a global variable equal to that value. Here's what I did.
public class Console {
String sql;
Statement stmt;
Connection conn;
ResultSet rs;
//Category Total
public static double num;
public Console(){
try{
Class.forName("com.mysql.jdbc.Driver");
System.out.println("Connecting to database...");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?autoReconnect=true&useSSL=false","user","password");
stmt = conn.createStatement();
System.out.println("Connected database successfully...");
sql = "SELECT sum(a) FROM table";
while(rs.next()) {
rs = stmt.executeQuery(sql);
num = rs.getDouble("sum(a)");
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
System.out.println(num);
}
}
When I run the program it prints 0.0 although the actual value is not.
You need to get your result set prior to the while loop, and then iterate through it
rs = stmt.executeQuery(...);
while (rs.next()) {
// and process your results row by row here...
}
Otherwise (as you've discovered) your rs variable is unset
Your result set won't contain sum(a) as a column name. You can get the result positionally (e.g. getInt() can take an index integer) or rename your result column (e.g. select sum(a) as sum FROM table) and reference it like that.
You haven't intialized the ResultSet with executing the query. Then you can loop the result set.
sql = "SELECT sum(a) FROM table";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
num = rs.getDouble("sum(a)");
}
You have been getting the results in the loop, but you have to do it before reach the loop.
You are getting 0.0 because of the behavior of JDBC driver.
From java doc
Returns: the column value; if the value is SQL NULL, the value
returned is 0
To know that last read value was null from Resultset, you can use method rs.wasNull() method. it will return true if the last column value read was SQL NULL and false otherwise.
It's good practice to assign a column alias to calculated results like sum(a) and retrieve the values using that alias.
Also good practice is to use Java's try-with-resources.
The try-with-resources statement ensures that each resource is closed at the end of the statement.
Also, if your SQL statement would return NULL, e.g. in case the table is empty or no rows apply to the conditions in your WHERE clause, the ResultSet.getDouble method will return the value 0.
sql = "SELECT sum(a) AS sum_a FROM table"; // assign alias sum_a to the expression sum(a)
try( ResultSet rs = stmt.executeQuery( sql ) ) { // get a resultset object in a try-with-resources statement, to auto-close it at the end
rs.next( ); // for the query you have, checking if there's a next row is actually not necessary; there's always a result for your query
num = rs.getDouble("sum_a"); // retrieve the column value by its alias
} // rs will be closed for you at this point

Execute multiple SQL statements in java

I want to execute a query in Java.
I create a connection. Then I want to execute an INSERT statement, when done, the connection is closed but I want to execute some insert statement by a connection and when the loop is finished then closing connection.
What can I do ?
My sample code is :
public NewClass() throws SQLException {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
System.out.println("Where is your Oracle JDBC Driver?");
return;
}
System.out.println("Oracle JDBC Driver Registered!");
Connection connection = null;
try {
connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:orcl1", "test",
"oracle");
} catch (SQLException e) {
System.out.println("Connection Failed! Check output console");
return;
}
if (connection != null) {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from test.special_columns");
while (rs.next()) {
this.ColName = rs.getNString("column_name");
this.script = "insert into test.alldata (colname) ( select " + ColName + " from test.alldata2 ) " ;
stmt.executeUpdate("" + script);
}
}
else {
System.out.println("Failed to make connection!");
}
}
When the select statement ("SELECT * from test.special_columns") is executed, the loop must be twice, but when (stmt.executeUpdate("" + script)) is executed and done, then closing the connection and return from the class.
Following example uses addBatch & executeBatch commands to execute multiple SQL commands simultaneously.
import java.sql.*;
public class jdbcConn {
public static void main(String[] args) throws Exception{
Class.forName("org.apache.derby.jdbc.ClientDriver");
Connection con = DriverManager.getConnection
("jdbc:derby://localhost:1527/testDb","name","pass");
Statement stmt = con.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String insertEmp1 = "insert into emp values
(10,'jay','trainee')";
String insertEmp2 = "insert into emp values
(11,'jayes','trainee')";
String insertEmp3 = "insert into emp values
(12,'shail','trainee')";
con.setAutoCommit(false);
stmt.addBatch(insertEmp1);
stmt.addBatch(insertEmp2);
stmt.addBatch(insertEmp3);
ResultSet rs = stmt.executeQuery("select * from emp");
rs.last();
System.out.println("rows before batch execution= "
+ rs.getRow());
stmt.executeBatch();
con.commit();
System.out.println("Batch executed");
rs = stmt.executeQuery("select * from emp");
rs.last();
System.out.println("rows after batch execution= "
+ rs.getRow());
}
}
Result:
The above code sample will produce the following result.The result may vary.
rows before batch execution= 6
Batch executed
rows after batch execution= = 9
Source: Execute multiple SQL statements
In the abscence of the schema or the data contained in each table I'm going to make the following assumptions:
The table special_columns could look like this:
column_name
-----------
column_1
column_2
column_3
The table alldata2 could look like this:
column_1 | column_2 | column_3
---------------------------------
value_1_1 | value_2_1 | value_3_1
value_1_2 | value_2_2 | value_3_2
The table alldata should, after inserts have, happened look like this:
colname
---------
value_1_1
value_1_2
value_2_1
value_2_2
value_3_1
value_3_2
Given these assumptions you can copy the data like this:
try (
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:orcl1", "test", "oracle")
)
{
StringBuilder columnNames = new StringBuilder();
try (
Statement select = connection.createStatement();
ResultSet specialColumns = select.executeQuery("SELECT column_name FROM special_columns");
Statement insert = connection.createStatement()
)
{
while (specialColumns.next())
{
int batchSize = 0;
insert.addBatch("INSERT INTO alldata(colname) SELECT " + specialColumns.getString(1) + " FROM alldata2");
if (batchSize >= MAX_BATCH_SIZE)
{
insert.executeBatch();
batchSize = 0;
}
}
insert.executeBatch();
}
A couple of things to note:
MAX_BATCH_SIZE should be set to a value based on your database configuration and the data being inserted.
this code is using the Java 7 try-with-resources feature to ensure the database resources are released when they're finished with.
you haven't needed to do a Class.forName since the service provider mechanism was introduced as detailed in the JavaDoc for DriverManager.
There are two problems in your code. First you use the same Statement object (stmt) to execute the select query, and the insert. In JDBC, executing a statement will close the ResultSet of the previous execute on the same object.
In your code, you loop over the ResultSet and execute an insert for each row. However executing that statement will close the ResultSet and therefor on the next iteration the call to next() will throw an SQLException as the ResultSet is closed.
The solution is to use two Statement objects: one for the select and one for the insert. This will however not always work by default, as you are working in autoCommit (this is the default), and with auto commit, the execution of any statement will commit any previous transactions (which usually also closes the ResultSet, although this may differ between databases and JDBC drivers). You either need to disable auto commit, or create the result set as holdable over commit (unless that already is the default of your JDBC driver).

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();

SELECT query using executeUpdate() instead of executeQuery()

for Ex:
class sample {
public static void main(String a[]) {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:orcl", "", "");
String str = "Slect * from EMP";
Statement st = con.createStatement();
try {
st.executeUpdate("select * from EMP"); //gives us Exception } catch(SQLException ex) { // I want actuval code here.......... //CODE here............
}//catch}//try}//main}//class
As others have pointed out: executeUpdate() can not be used to run queries.
If you are looking for a way to execute statement without knowing what they do, you should have a look at the execute() method.
http://download.oracle.com/javase/6/docs/api/java/sql/Statement.html#execute%28java.lang.String%29
The returned boolean will tell you if it returned a result or just update counts. You can then use getResultSet() to obtain the result or getUpdateCount() to get number of affected rows.
Note that a statement is allowed to return more than one result and/or udpate count. See the example in getMoreResults().
the below code exlpains that the execute update statement gives exception in the case of
JdbcOdbcDriver but not in case of OracleDriver
so it is not always necesarry that select statement will give exception in executeUpdate("Select * ...");
but it depends on the Drive we register in DriverManager.registerDriver(Driver ob);
some Driver May give Exception while some will not
but the answer to your question is you should not use executeUpdate("Sel..")
for select Statement even if doesn't give Exception read the below code and and comment you will understand better
import java.sql.*;
import sun.jdbc.odbc.*;
import oracle.jdbc.driver.*;
public class MyDb {
public static void main(String args[]) throws Exception {
//drive is oracle.jdbc.driver.OracleDriver;
OracleDriver od = new OracleDriver();
DriverManager.registerDriver(od);
Connection conn;
conn = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE", "system", "system");
Statement stm = conn.createStatement();
int val = stm.executeUpdate("select * from mylog");
System.out.println(val);
//output for above code is 10 actually the table had 15 rows
//but when table had 7 rows output was 7 ,when number of rows where 9 output was 9
//but when the number of row in table were more than or equal to 10 the out put was 10
//so actually it is no meaning to use select statement within executeQuery
//even if it doesn't give exception
//driver is sun.jdbc.odbc.JdbcOdbcDriver;
JdbcOdbcDriver od2 = new JdbcOdbcDriver();
DriverManager.registerDriver(od2);
Connection conn2 = DriverManager.getConnection("jdbc:odbc:swap", "system", "system");
Statement stm2 = conn2.createStatement();
int val2 = stm2.executeUpdate("select * from mylog");
//while this code gives exception
//Exception in thread "main" java.sql.SQLException: No row count was produced
// at sun.jdbc.odbc.JdbcOdbcStatement.executeUpdate(Unknown Source)
// at MyDb.main(MyDb.java:19)
System.out.println(val2);
}
}
executeUpdate is intended for statements that modifies data (update, insert). This is why you get an exception /by the way why do you want to use executeUpdate here?)
String str = "Slect * from EMP";
Should be
String str = "Select * from EMP";
as well.

Categories

Resources