JDBC ResultSet not iterating all rows - java

I need a second pair of eyes on some code. I feel like there's something simple I'm missing. I have a table in my MariaDB called jeff_tables, which contains 4 entries. I've created a utility thread that runs the following code inside the run method:
try {
getConnection();
String query = "SELECT * FROM jeff_tables";
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(query);
//rs.last(); //returns 4 rows
//System.out.println("result set size: " + rs.getRow() );
while(rs.next()) {
Integer tenant = rs.getInt("TENANT_ID");
String table = rs.getString("TABLE_NAME");
System.out.println("Inserting k-v pair: " + tenant + " " + table);
tableNames.put(tenant, table);
}
} catch (SQLException e) {
e.printStackTrace();
}
When I uncomment the rs.last() and rs.getRow() lines, it returns 4, which is the correct number of entries it should return. However, what's actually happening is it enters my while loop, prints the correct values for the first row, then throws a null pointer on the put statement. I've also tried running this code outside of a thread, but it's doing the same thing. Any advice would be greatly appreciated. Thanks in advance.

As soon as I posted this, I saw the problem. This was just a simple instance of forgetting to instantiate the HashMap before trying to insert values into it. It's funny how sometimes it takes posting a question to open your eyes.

Related

While Loop inside an If-else statement (Java)

I'm writing a Java program in which it updates existing data in a local database with new details whenever a record that has the same product model in another database is found. If no record is found, it inserts a new record instead.
I'm using an if-else statement to check if record does exist or not. The current code works ONLY for a single record. I want it to keep on updating the local database as long as the product model in local database and in the other database exists.
Here's the code, I'm currently using:
public static void checkExist() {
try {
Statement stmt = conn.createStatement();
int prod_qnty, prod_weight;
float prod_price;
String prod_model = "97801433"; //testing purposes
ResultSet rs = stmt.executeQuery("SELECT * from products where products_model = " + prod_model );
if (rs.next()){
//while (rs.next()) {
prod_qnty = rs.getInt("products_quantity");
prod_price = rs.getFloat("products_price");
prod_weight = rs.getInt("products_weight");
System.out.println(prod_qnty + "\t" + prod_price + "\t" + prod_weight);
updDB(prod_model, prod_qnty, prod_price, prod_weight);
//}
}
else{
insertDB(prod_model, prod_qnty, prod_price, prod_weight);
}
stmt.close();
} catch (SQLException ex) {
//Logger.getLogger(Check.class.getName()).log(Level.SEVERE, null, ex);
}
}
I've added a while loop within the if statement where record exists, however, after I've added the while loop. Now it can't even print out any record. It seems like once it goes inside the if (rs.next()) condition, it doesn't go inside the while loop.
Will anyone let me know what I'm doing wrong? Is it possible to use a while loop inside an if-else statement? As usually it is used the other way around, if-else statement within the while loop.
Any help will be greatly appreciated. Thank you.
You do not have to add a separate if statement while (rs.next()) { //CODE }
if you call next() 2 times, cursor will move 2 records forward and if you have only one record for the query, it will not go into the while loop.
CODE will execute only if there is a results remaining.

Java, use array instead of SQL SELECT

I have one script which fetches around 25.000 different ID values and uses them to make some changes in other table. But the programmer created this code which searches ID (dialid in the code) through the table of 10 million records (line 3) and every query in loop is executing around 1 second. My idea is to fetch last 30 days of records with the SQL and to put it into an array and check only the array.
And my question is, how to do that in Java? Is it the in_array function? I'm solid in PHP, but beginner in Java code...
private Integer getDialId(int predictiveId) {
Integer dialid = null;
StringBuilder sql = new StringBuilder("SELECT dialid from dial where PREDICTIVE_DIALID=");
sql.append(predictiveId); //this predictiveId is calculated in other part of code
ResultSet rsDialId = null;
Statement s1 = null;
try {
s1 = oracle.getConn().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
rsDialId = s1.executeQuery(String.valueOf(sql));
if (rsDialId.next()) {
dialid = rsDialId.getInt("dialid");
}
} catch (SQLException ex) {
Logger.getLogger(MediatelCdrSync.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (s1 != null) {
s1.close();
}
if (rsDialId != null) {
rsDialId.close();
}
} catch (SQLException ex) {
Logger.getLogger(MediatelCdrSync.class.getName()).log(Level.SEVERE, null, ex);
}
}
System.out.println("DIALID = " + dialid);
return dialid;
}
Thnx
If you have a performance problem I'd start to see why the query takes one second per execution, if it's database time because the dial table does not have and index on PREDICTIVE_DIALID column you can do very little at the java level.
Anyway the jdbc code reveals some problems especially when used with an oracle database.
The biggest issue is that you are hardcoding your query parameter causing Oracle to re"hard parse" the query every time; the second (minor one) is that the resultset is scrollable and updatable while you need only to load the first row. If you want to make some little modification to your code you should change to somethig like this pseudo code:
PreparedStatement ps =connection.prepareStatement("SELECT dialid from dial where PREDICTIVE_DIALID=?");
for (int i=0;i<10;i++) {//your 25000 loop elements is this one
//this shoudl be the start of the body of your getDialId function that takes also a prepared statement
ps.setInt(1, i);
ResultSet rs=ps.executeQuery();
if (rs.next()) {
rs.getInt("dialid");
}
rs.close();
//your getDialId end here
}
ps.close();
With this minimal java solution you should note a performance increase, but you must chek the performance of the single query since if there is a missing index you cand very little at a java code.
Another solution, more complicated, is to to create a temporart table, fill it with all the 25000 predictiveId values and then issue a query that joins dial and you temporary table; so with one resultset(and one query) you can find all the dialid you need. A jdbc batch insert into the temp table speeds up insertion time noticeably.
If you are planning to fetch less record and store that result in some array then
I think it is better for you to limit your search by creating a view in Database with limited record's (say record for last 2 year's)
And Use that view in your select query
"SELECT dialid from dial_view WHERE PREDICTIVE_DIALID = "
Hope it will help :)

MySQL before start of exception [duplicate]

This question already has answers here:
ResultSet exception - before start of result set
(6 answers)
Closed 5 years ago.
I get an error stating that I got an exception before start of a result set. I'm trying to get a value (score from the MySQL database) and add one to the Java rank based on the player score. This is to create a scoreboard.
So if the player's score is lower than the current score, it gets posted with rank 1. If it's higher, the program checks the score against the next entry in the MySQL database. I haven't yet implemented a feature to change all the current entries rank's to increment by 1.
Bottom Line: I'm creating a scoreboard using MySQL and Java. The Java program creates a score entry based on input, and then sends it off to the MySQL database.
System.out.println("Your score is: "+score*2+" (A lower score is better.)");
try {
// create a java mysql database connection
String myDriver = "com.mysql.jdbc.Driver";
String myUrl = "jdbc:mysql://4.30.110.246:3306/apesbridge2013";
String dbName = "apesbridge2013";
String tbName = period + "period";
Class.forName(myDriver);
Connection conn = DriverManager.getConnection(myUrl, "user", CENSORED);
next = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet resultSet = next.executeQuery("SELECT * FROM " + tbName);
int cscore = resultSet.getInt("score");
for(int sscore = score; sscore > cscore;){
resultSet.next();
cscore = resultSet.getInt("score");
rank++;
}
stmt = conn.createStatement();
stmt.executeUpdate("insert into " + dbName + "." + tbName + " " + "values(" + rank + ", '" + name + "', " + score + ")");
stmt.close();
conn.close();
}
catch (Exception e)
{
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
}
Put resultSet.next(); right below your executeQuery line.
As stated by #hd1, you need to call ResultSet.next() after the call to executeQuery:
while (resultSet.next()) {
...
Also, better to use PreparedStatement instead of java.sql.Statement and use parameter placeholders to protect against SQL Injection attacks:
There's a problem in your for loop; the exit condition should be when there are no more rows to fetch. Your query doesn't guarantee that the exit condition will ever be met, and you may attempt to fetch past the end of the resultset. (And even when your for loop does happen to be entered, and when if the for loop does happen to be exited, the rank value derived by that loop is non-deterministic, it's dependent on the order that rows are returned by the database.
I also don't see any call to resultSet.close() or next.close().
There's so many problems here, it's hard to know where to begin.
But firstly, it would be much more efficient to have the database return the rank to you, with a query:
"SELECT COUNT(1) AS rank FROM " + tbName + " WHERE score < " + score
rather than pulling back all the rows back, and comparing each score. That's just painful, and a whole lot of code that is just noise. That would allow you to focus on the code that DOES need to be there.
Once you get that working, you need to ensure that your statement is not vulnerable to SQL injection, and prepared statements with bind variables is really the way to go there.
And you really do need to ensure that calls are made to the close() methods on the resultset, prepared statements, and the connection. We typically want these in a finally block. Either use nested try/catch blocks, where the variables are immediately initialized, like this:
try {
Connection conn = DriverManager.getConnection(...
try {
stmt = conn.CreateStatement();
String query = "SELECT COUNT(1) AS `rank` FROM " + tbName + " WHERE `score` < " + score ;
try {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
rank = rs.getInt("rank");
}
} finally {
if (rs!=null) { rs.close() };
}
} finally {
if (stmt!=null) { stmt.close() };
}
} finally {
if (conn!=null) { conn.close() };
}
Or one big try/catch block can also be workable:
} finally {
if (resultSet!=null) { resultSet.close() };
if (next!=null) { next.close() };
if (conn!=null) { conn.close() };
)
The point is, the close methods really do need to be called.

how to sum up values from oracle database into java?

I have a java application which is connected to an Oracle database. I have a form where the user enters an ID called COMMUNITY_ID, a start date called START_DATE and an end date called END_DATE.
I want the application to search through the table in database for the entered values, and when the search result is correct I want it to display the sum of total values.
I have three methods; each method is responsible for searching a single text box. For example, the first method total 1 searches for the COMMUNITY_ID, and the second method searches for the START_DATE and the last one searches for the END_DATE.
I get an error message saying the result set is empty or closed. I am not sure why because I dont understand the message clearly.
The following is my code. If anyone has idea how to fix it that, please help me.
public void total3()
{
ResultSet result;
System.out.println("total 3");
String endDate = this.EndTxtBox.getText();
try
{
rs=st.executeQuery("select RECIPT_ID,COMMUNITY_ID,VALUE,START_DATE,END_DATE, ITEM_BOUGHT,REASON from RECIPTS where END_DATE = '" +endDate+"'");
//display();
this.EndTxtBox.setText(rs.getString("END_DATE"));
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Searched Failed" + ex);
}
try
{
result = rs=st.executeQuery("select SUM(VALUE)from RECIPTS where END_DATE = '" +endDate+"'" );
//result = rs=st.executeQuery("select RECIPT_ID,COMMUNITY_ID,VALUE,START_DATE,END_DATE, ITEM_BOUGHT,REASON,SUM(VALUE)from RECIPTS group by RECIPT_ID,COMMUNITY_ID,VALUE,START_DATE,END_DATE, ITEM_BOUGHT,REASON ");
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error" + ex);
}
}
Any ideas, please? What is wrong with it?
You're trying to read from the result set before going to its first row:
if (rs.next()) {
endDate = rs.getString("END_DATE");
}
Your code is full of bad practices:
mixing UI code with database access code
catching Exception
selecting a whole lot of rows and columns when you're only interested by one of them
not using prepared statements
using both result and rs for the same thing
not closing statements and result sets
using String variables to store dates
poor and inconsistent indentation

Need advice on fixing my JAVA query statement?

My JAVA script consists of 2 JAVA classes: RMS, queryRMS
In the RMS class I call the method in the queryRMS class
RMS Java Class (I left out the start execution part, below is just the method)
for (int i = 1; i <= itemCount; i++) {
GlobalVariables.numberRow = i;
JavaDatapool.settings();
String item = queryRPM.connectDB_Multi(configFile,"SELECT ITEM FROM ORDSKU WHERE ORDER_NO = '" + orderNo + "' ORDER BY ITEM ASC",i);
JavaDatapool.writeXLS("item",item,GlobalVariables.sheetXLS);
sleep(1);
}
queryRMS JAVA class
public static String connectDB_Multi(String configFile, String query, int i) throws FileNotFoundException, IOException, SQLException, ClassNotFoundException{
Properties p = new Properties();
p.load(new FileInputStream(configFile));
String serverName = (p.getProperty("RMS_DBServerName"));
String portNumber = (p.getProperty("RMS_PortNumber"));
String sid = (p.getProperty("RMS_SID"));
String url = "jdbc:oracle:thin:#//" + serverName + ":" + portNumber + "/" + sid;
String username = (p.getProperty("RMS_Username"));
String password = (p.getProperty("RMS_Password"));
// jdbc:oracle:thin:#//localhost:1521/orcl
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = DriverManager.getConnection(url,username,password);
String setr = null;
try {
Statement stmt = connection.createStatement();
try {ResultSet rset = stmt.executeQuery(query);
try {
while(rset.absolute(i))
setr = rset.getString(1);
return setr;
}
finally {
try { rset.close();
}
catch (Exception ignore) {}
}
}
finally {
try { stmt.close();
}
catch (Exception ignore) {}
}
}
finally {
try { connection.close();
}
catch (Exception ignore) {}
}
}
So what it does is call the connectDB_multi class and then returns the String where the next part is saving it inside an Excel worksheet.
The loop should return all rows, one at a time and then save it inside the Excel worksheet.
In the second time in loop the query is faulted, eventhough the query should return 1 column consisting of 2 rows.
the original contained the part while(rset.next()) instead of while(rset.absolute(i))
but next only return the first row everytime. so the script works when only one column and row is retrieved from the Database.
Your logic looks a bit messed up.
Look at the first loop you posted. You are, effectivly, executing:
SELECT ITEM FROM ORDSKU WHERE ORDER_NO = '" + orderNo + "' ORDER BY ITEM ASC
itemCount number of times. Each time you execute it, you are attempting to access the n:th row, n being loop counter. Do you see a problem there? How do you know that the query will return itemCount number of rows? Because if it doesn't, it will fail since you are attempting to access a row that doesn't exist.
What I suspect you WANT to do is something like this
Statement stmt = connection.createStatement();
ResultSet rset = stmt.executeQuery(query);
while(rset.next()) {
JavaDatapool.writeXLS("item",rset.getString(1),GlobalVariables.sheetXLS);
}
You should also seriously consider using some form of connection pooling to avoid having to re-open new connections all the time as that is a pretty time-consuming operation.
This code seems very inefficient, for each row you want to fetch from the database you read a property file, create a connection, select all matching rows, skip ahead to the row you want and return just that row. (Or at least I think that is what you are trying to do).
Your code
while(rset.absolute(i))
setr = rset.getString(1);
is probably an infinite loop as it will continue to go to the same row as long as it is ok to go to that row, so either that row does not exist (and the while exists) or the row does exist (and while continues forever).
You should probably restructure your program to only do one select and read all rows that you want and store them in your excel file. While doing this, you can debug to see if you actually are getting the data you expect.
Apart from the inefficient code of creating new connections and querying once for each row, how do you know how many rows you want?
I think in the end you want something like this
....
while(rset.next()) {
JavaDatapool.writeXLS("item",item,GlobalVariables.sheetXLS);
}
And what is the sleep(1) support to accomplish?
FYI: if you open and close statement too often as your logic or pap's solution, you can get the " java.sql.SQLException: ORA-01000: maximum open cursors exceeded" error message.
I suggest you to not do 'too much generalize'. I saw a lot of OOP programmers overdid generalization and that is painful. You should design by a goal and the goal should not be 'just alignment' nor 'code look beautiful', it has to have a purpose for designing.

Categories