Read the Following Code:
public class selectTable {
public static ResultSet rSet;
public static int total=0;
public static ResultSet onLoad_Opetations(Connection Conn, int rownum,String sql)
{
int rowNum=rownum;
int totalrec=0;
try
{
Conn=ConnectionODBC.getConnection();
Statement stmt = Conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
String sqlStmt = sql;
rSet = stmt.executeQuery(sqlStmt);
total = rSet.getRow();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("Total Number of Records="+totalrec);
return rSet;
}
}
The folowing code dos't show actual total:
total = rSet.getRow();
my jTable display 4 record in jTable but total = 0; when I evaluate through debug, it shows:
total=(int)0;
rather than total=(int)4
And if I use
rSet=last(); above from the code total = rSet.getRow();
then total shows accurate value = 4 but rSet return nothing. then jTable is empty.
Update me!
BalusC's answer is right! but I have to mention according to the user instance variable such as:
rSet.last();
total = rSet.getRow();
and then which you are missing
rSet.beforeFirst();
the remaining code is same you will get your desire result.
You need to call ResultSet#beforeFirst() to put the cursor back to before the first row before you return the ResultSet object. This way the user will be able to use next() the usual way.
resultSet.last();
rows = resultSet.getRow();
resultSet.beforeFirst();
return resultSet;
However, you have bigger problems with the code given as far. It's leaking DB resources and it is also not a proper OOP approach. Lookup the DAO pattern. Ultimately you'd like to end up as
public List<Operations> list() throws SQLException {
// Declare Connection, Statement, ResultSet, List<Operation>.
try {
// Use Connection, Statement, ResultSet.
while (resultSet.next()) {
// Add new Operation to list.
}
} finally {
// Close ResultSet, Statement, Connection.
}
return list;
}
This way the caller has just to use List#size() to know about the number of records.
The getRow() method retrieves the current row number, not the number of rows. So before starting to iterate over the ResultSet, getRow() returns 0.
To get the actual number of rows returned after executing your query, there is no free method: you are supposed to iterate over it.
Yet, if you really need to retrieve the total number of rows before processing them, you can:
ResultSet.last()
ResultSet.getRow() to get the total number of rows
ResultSet.beforeFirst()
Process the ResultSet normally
As others have answered there is no way to get the count of rows without iterating till the end. You could do that, but you may not want to, note the following points:
For a many RDBMS systems ResultSet is a streaming API, this means
that it does not load (or maybe even fetch) all the rows from the
database server. See this question on SO. By iterating to the
end of the ResultSet you may add significantly to the time taken to
execute in certain cases.
A default ResultSet object is not updatable and has a cursor
that moves forward only. I think this means that unless you
execute
the query with ResultSet.TYPE_SCROLL_INSENSITIVE rSet.beforeFirst() will throw
SQLException. The reason it is this way is because there is cost
with scrollable cursor. According to the documentation, it may throw SQLFeatureNotSupportedException even if you create a scrollable cursor.
Populating and returning a List<Operations> means that you will
also need extra memory. For very large resultsets this will not
work
at all.
So the big question is which RDBMS?. All in all I would suggest not logging the number of records.
One better way would be to use SELECT COUNT statement of SQL.
Just when you need the count of number of rows returned, execute another query returning the exact number of result of that query.
try
{
Conn=ConnectionODBC.getConnection();
Statement stmt = Conn.createStatement();
String sqlStmt = sql;
String sqlrow = SELECT COUNT(*) from (sql) rowquery;
String total = stmt.executeQuery(sqlrow);
int rowcount = total.getInt(1);
}
The getRow() method will always yield 0 after a query:
ResultSet.getRow()
Retrieves the current row number.
Second, you output totalrec but never assign anything to it.
You can't get the number of rows returned in a ResultSet without iterating through it. And why would you return a ResultSet without iterating through it? There'd be no point in executing the query in the first place.
A better solution would be to separate persistence from view. Create a separate Data Access Object that handles all the database queries for you. Let it get the values to be displayed in the JTable, load them into a data structure, and then return it to the UI for display. The UI will have all the information it needs then.
I have solved that problem. The only I do is:
private int num_rows;
And then in your method using the resultset put this code
while (this.rs.next())
{
this.num_rows++;
}
That's all
The best way to get number of rows from resultset is using count function query for database access and then rs.getInt(1) method to get number of rows.
from my code look it:
String query = "SELECT COUNT() FROM table";
ResultSet rs = new DatabaseConnection().selectData(query);
rs.getInt(1);
this will return int value number of rows fetched from database.
Here DatabaseConnection().selectData() is my code for accessing database.
I was also stuck here but then solved...
Related
I'm creating parcel machine program. Every parcel has unique parcelID which is exported to mysql db. The problem is that every time when I run the program, the program is counting parcelID from 0. I'm looking for a solution which will allow me to check the last parcelID in the database and create row after the last one.
Now it looks like this: 1. I'm creating a new row in db (successfully) by java program. 2. I'm closing the program after some time. 3. I run the program again and I can't add another new row because there is error "duplicate entry '1' for key 'PRIMARY'".
public static void post() throws Exception{
int parcelID = Parcel.generateID();
int clientMPNumber = Parcel.typeClientNumber();
int orderPassword = Parcel.generatePass();
try{
Connection con = getConnection();
PreparedStatement posted = con.prepareStatement("INSERT INTO Parcels.Orders (parcelID, clientMPNumber, orderPassword) VALUES ('"+parcelID+"', '"+clientMPNumber+"', '"+orderPassword+"')");
posted.executeUpdate();
}
catch(Exception e){
System.out.println(e);
}
finally{
System.out.println("Insert completed");
}
}
and the method is:
public static int generateID(){
parcelID = parcelID + 1;
return parcelID;
}
I'd let the database do the heavy lifting for you - Just define the parcelID column as serial instead of trying to set its value yourself.
You shouldn't use Id generation, just create auto_increment column in database table
As described here , define your primary key column to auto increment for each insert so your java code doesn't have to manually calculate primary key value each time.
If that is not a possibility, you need to show how you declare & initialize parcelID. As of your current code, parcelID looks to be a class level field that gets initialized to zero for each run so you always get the same value - 1. You need to initialize with last value from data base.
Also, implement suggestion as mentioned in comment to your question regarding PreparedStatement
There are a couple of things to attent to.
// parcelID should be an INT AUTOINCREMENT primary key.
try (PreparedStatement posted = con.prepareStatement(
"INSERT INTO Parcels.Orders (clientMPNumber, orderPassword) "
+ "VALUES (?, ?)",
Statement.RETURN_GENERATED_KEYS);
posted.setString(1, clientMPNumber);
posted.setString(2, orderPassword);
posted.executeUpdate();
try (ResultSet rsKey = posted.getGeneratedKeys()) {
if (rsKey.next()) {
int parcelID = rsKey.getInt(1);
return parcelID; // Or such
}try-with-resources
}
}
The database can deal with automatic numbering best, so that two transactions at the same time do not steal the same "next" number.
You should close things like Connection, PreparedStatement and ResultSet. This can best be done using the a bit awkward syntax of try-with-resources. That closes automatically even on exception and return.
PreparedStatements should be used with placeholders ?. This takes care for escaping special characters like ' in the password. Also prevents SQL injection.
Stylistic better use SQLException above Exception. Better maybe even a throws SQLException.
I have two methods in my class, First I am calling method dbExecuteStatement(), which execute the sql query. After execution of sql query, I get a ResultSet object. I am saving this ResultSet object in a static hashMap, so that on my next method call fetchResults(), I can use the existing result set to retrieve the results. Reason for saving the ResultSet object in a map is ,in fetchResults() method request parameter, I will get the max fetch row size, and on basis of that value I will be iterating the result set. Both of this methods are supposed to be called individual from the client side.
Now the problem, I am facing is that, When I am iterating the ResultSet object in fetchResults() method, I am getting the row count zero. If I fetch the same ResultSet from a hashMap in dbExecuteStatement(), I get the actual row count i.e 5 in my case. I checked the ResultSet object that I have put in the hash map in fetchResults() method and dbExecuteStatement(), it is the same object. But If get the ResultSetMetaData object in fetchResults() method and dbExecuteStatement(), they are coming different. Can someone help me in understanding the cause, Why I am getting the result count zero.
Below is the code:
public class HiveDao1 {
private static Map<Object,Map<Object,Object>> databaseConnectionDetails
= new HashMap<Object,Map<Object,Object>>();
//This method will execute the sql query and will save the ResultSet obj in a hashmap for later use
public void dbExecuteStatement(DbExecuteStatementReq dbExecuteStatementReq){
//I already have a connection object saved in map
String uniqueIdForConnectionObject = dbExecuteStatementReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
Connection connection = (Connection) dbObject.get(DatabaseConstants.CONNECTION);
try {
Statement stmt = connection.createStatement() ;
// Execute the query
ResultSet resultSet = stmt.executeQuery(dbExecuteStatementReq.getStatement().trim()) ;
//save the result set for further use, Result set will be used in fetchResult() call
dbObject.put(DatabaseConstants.RESULTSET, resultSet);
/*
* Now below is the debugging code,which I put to compare the result set
* iteration dbExecuteStatement() and fetchResults method
*/
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("==ResultSet fethced in dbExecuteStatement=="+rs);
System.out.println("==ResultSet metadata fetched in dbExecuteStatement ==="+rs.getMetaData());
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
System.out.println("No of rows found from result set in dbExecuteStatement is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* This method fetch the result set object from hashMap
* and iterate it on the basis of fetch size received in req parameter
*/
public void fetchResults(FetchResultsReq fetchResultsReq){
String uniqueIdForConnectionObject = fetchResultsReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
try {
//Fetch the ResultSet object that was saved by dbExecuteStatement()
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("ResultSet fethced in fetchResults at server side dao layer======"+rs);
System.out.println("ResultSet metadata fetched in fetchResults at server side dao layer======"+md);
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
//Here the row count is not same as row count in dbExecuteStatement()
System.out.println("No of rows found from result set in fetchResults is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Expanding on my comment (And #Glenn's):
Using a ResultSet more than once
When you write debug code that iterates a ResultSet, the cursor moves to the end of the results. Of course, if you then call the same object and use next(), it will still be at the end, so you won't get any more records.
If you really need to read from the same ResultSet more than once, you need to execute the query such that it returns a scrollable ResultSet. You do this when you create the statement:
Statement stmt = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY );
The default statement created by connection.createStatement() without parameters returns a result set of type ResultSet.TYPE_FORWARD_ONLY, and that ResultSet object can only be read once.
If your result set type is scroll insensitive or scroll sensitive, you can use a statement like rs.first() to reset the cursor and then you can fetch the records again.
Keeping the statement in scope
#Glenn's comment is extremely important. The way your program works right now, it may work fine throughout the testing phase, and then suddenly in production, you'll sometimes have zero records in your ResultSet, and the error will be reproducible only occasionally - a debug nightmare.
If the Statement object that produces the ResultSet is closed, the ResultSet itself is also closed. Since you are not closing your Statement object yourself, this will be done when the Statement object is finalized.
The stmt variable is local, and it's the only reference to that Statement that we know of. Therefore, it will be claimed by the garbage collector. However, objects that have a finalizer are relegated to a finalization queue, and there is no way of knowing when the finalizer will be called, and no way to control it. Once it happens, the ResultSet becomes closed out of your control.
So be sure to keep a reference to the statement object alongside your ResultSet. And make sure you close it properly yourself once you are done with the ResultSet and will not be using it anymore. And after you close it remember to remove the reference you have kept - both for the statement and the result set - to avoid memory leaks. Closing is important, and relying on finalizers is a bad strategy. If you don't close it yourself, you might run out of cursors at some point in your database (depending on the DBMS and its configuration).
I'm trying to access my database, inject some SQL Code and return the value out of it.
First of all, I'm a new to this stuff but I've came up with the following code:
public static ResultSet checkCmdAmount() throws Exception {
try {
// This will load the MySQL driver, each DB has its own driver
Class.forName("com.mysql.jdbc.Driver");
// Setup the connection with the DB
connect = DriverManager.getConnection(""+MyBot.mysqlDbPath+"",""+MyBot.mysqlDbUsername+"",""+MyBot.mysqlDbPassword+"");
PreparedStatement zpst=null;
ResultSet zrs=null;
zpst=connect.prepareStatement("SELECT COUNT(1) FROM eigenebenutzerbefehle");
zrs=zpst.executeQuery();
return zrs;
}catch (Exception e) {
throw e;
} finally {
close();
}
}
In my return, I get the following:
ResultSet: com.mysql.jdbc.JDBC4ResultSet#196da649
But I want actually the Amount of rows in my table.
When I execute the sql code through phpmyadmin I get 3 which is correct.
What is wrong here?
You need to read and get the desired values from the ResultSet. Do it as below:
public static int checkCmdAmount() throws Exception {
// ...
int count = 0;
while (zrs.next()) {
// Get the values from the current row...
count = zrs.getInt(1);
}
return count;
}
A ResultSet object contains all rows returned by executing an SQL query using a PreparedStatment or Statement from a database.
So when you executed
ResultSet zrs=null;
zpst=connect.prepareStatement("SELECT COUNT(1) FROM eigenebenutzerbefehle");
zrs=zpst.executeQuery();
return zrs;
as you said your SQL query will return number of rows, and that information is stored in ResultSet object zrs, but a ResultSet object's job is to store all the rows containing values from all columns specified or all rows in case of using *.
And when you are returning zrs you are returning a ResultSet object, and when you try and print an object what you get is the default value for an object's toString() conversion, which is in most cases objects types fully qualified name + a few extra characters.
And your updated code executes
if(zrs.next()){
return zrs.getInt(1);
}
else{
return -1;
}
here zrs.next() call moves the zrs to valid next record(or row) from where values can be retrieved, it also returns true or false depending upon the presence of record. In your example if you add one more call to zrs.next() then it would be returning false.
zrs.getInt(1) will return the value in the row the zrs pointing to and the value of the first column, it has in that row, which is in your case only column.
How to find out, that a user is already registered, for e.g. in a web application? Like I have a database of 1 million users. Every time comparing every single row in database is inefficient. Is there any other optimal approach?
Every time comparing every single row in database is inefficient
I gather that you're hauling the entire DB table contents into Java's memory by a SELECT * FROM User and then looping over every row in a while loop and comparing its username by equals() like below, is that true?
public boolean exists(String username) throws SQLException {
// ... Declare, etc.
statement = connection.prepareStatement("SELECT * FROM User");
resultSet = statement.executeQuery();
while (resultSet.next()) {
if (username.equals(resultSet.getString("username"))) {
return true;
}
}
return false;
// ... Close, etc (in finally!)
}
Then that's indeed very inefficient. You should be indexing the username column (it probably already is, with UNIQUE constraint) and then make use of SQL WHERE clause. It'll return exactly zero or one rows and the DB will do its very best finding it, which is usually much, much faster than the above Java approach.
public boolean exists(String username) throws SQLException {
// ... Declare, etc.
statement = connection.prepareStatement("SELECT id FROM User WHERE username = ?");
statement.setString(1, username);
resultSet = statement.executeQuery();
return resultSet.next();
// ... Close, etc (in finally!)
}
In a nutshell, as long as you make proper use of DB indexes and write SQL queries as such that it returns exactly the information you need, without any necessity for filtering using Java or additional queries afterwards, then it'll be most efficient approach.
You can optimize your query.You can maintain a unique username(or your unique parameter) for user and when someone trying to register,You can pass that usename to query and check it is already registered or not
I retrieve a ResultSet with a lot of rows. Each row has to be analyzed, so I'd like to analyze each row in a new thread (don't worry: I won't start all the threads simultaneously, let say 10 in a row). The entire ResultSet will be used exclusively to read data from it (so, it's a kind of a static read-only table).
So what I'd like to do is:
ResultSet rs;
public void loadResultSet(){
...
rs = _preparedStatement.executeQuery();
int rowSize = 0;
while (rs.next()) {
rowSize++;
}
//this method starts 10 threads simultaneously
runThreads(rowSize);
...
}
And...
#Override
public void run() {
//Unknown object that allows me to store a copy of a single row from ResultSet
Foo foo = rs.absolute(index);
//Then i can retrieve data just like a normal ResultSet
String s = foo.getString(1);
....
....
}
Any suggestion?
Samples are really appreciated! Thanks!
If I were u, I would rather to execute the queries in separate threads also like:
select * from table_name where mod(id,threadCount)=threadId
Just give an id to each thread and execute them. With this, each thread will have different datas to process