How to pass sql result set into two method? - java

I want to pass sql result set into two method. Problem is two method separately execute while(rs.next) function separately. Then after one method execute other method got 0 result set. How can I pass result set into two method?
public void demo(){
/* Result set got from the corpusSentenceRetrive method */
ResultSet rsNew=corpusSentenceRetrive(wordAll);
method1(rsNew);
method2(rsNew);
}
public void method1(ResultSet rst){
ResultSet rs = rst;
while (rs.next()) {....}
}
public void method2(ResultSet rst){
ResultSet rs = rst;
while (rs.next()) {....}
}
When one method executed other method receive 0 result set. I want to execute both. How can I solve?
I tried store result set array list two location and use that two location result set. But that also not solved the problem.

Consume the data in the ResultSet in a single method and return List<Whatever> whateverList, then use this whateverList in your methods with real data.
Another approach may be using ResultSet.TYPE_SCROLL_SENSITIVE when creating your Statement or PreparedStatement and go to the first line after calling the 1st method and before calling the 2nd method.
IMO I would use the former rather than the latter.

Don't pass the raw result set to multiple methods. Make one method that reads the data from the result set, puts it into a collection of Java objects, and then pass that collection around as much as you wish.
class DataObject {
public DataObject(int id, String name, String ...) {
...
}
public int getId() {...}
}
List<DataObject> readAll() {
... // Read the data and put it in the list
}
...
List<DataObject> data = readAll();
method1(data);
method2(data);
Alternatively, you could rewrite method1 and method2 to operate on a single row, rather than on the entire result set. Then the reader method could deal with the loop, and call method1 and method2 for each row returned from the database:
while (rs.next()) {
singleRowMethod1(rs);
singleRowMethod2(rs);
}

We can Move resultSet cursor to before the first row using ResultSet APIs.
Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet resultSet = stmt.executeQuery("SELECT * FROM my_table");
// Move cursor forward as you normally traverse through ResultSet
while (resultSet.next()) {
// Get data at cursor
String s = resultSet.getString(1);
}
// move cursor before first row
resultSet.beforeFirst();`
Pass this resultSet to any method and iterate as usual in loops.

Related

array not being filled

This should have at least 3 entries in the array when I view it at a later stage, but it only displays one. I believe this is thee problematic method, any advice?
String[] getKidsNamebyCid(int cid) {
String[] out = new String[20];
try {
String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";//setting query command
ps = connect.prepareStatement(qry);//preparing statement
ps.setInt(1, cid);//setting CID
ps.executeQuery();//running command
int i = 0;
while (ps.getResultSet().next()) {
out[i] = ps.getResultSet().getString("KIDSNAME");
i++;
}
} catch (SQLException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
The getResultSet() call isn't a getter. That method does things to the DB, and you can't just repeatedly call it; the first time you get a ResultSet object (which you need to close), the second time everything is reset. So don't; you need to call getResultSet() once.
How do I know? By reading. Straight from getResultSet() documentation:
This method should be called only once per result.
Also this code is littered with severe code issues more generally focussed around resources. Resources are objects which aren't -just- a bunch of bits in memory, they represent (and hold open) a 'resource'. In the case of DBs, it's connections to the DB engine. You can't just make resources, you have to always put them in 'guarding' blocks that guarantee the resources are cleaned up. As a consequence, you never want them to be a field unless there's no other way (and then the thing they are a field inside of becomes a resource).
So, the fact that your PreparedStatement is a field? No good. The fact that you call .getResource just like that, unguarded? No good.
Finally, your exception handling is silly. The default act when facing checked exceptions is to just add them to your throws clause. If you can't do that, the right move is throw new RuntimeException("uncaught", e);, not what you did.
executeQuery already returns a resultset. Generally, never call getResultSet*.
Finally, arrays are more or less obsolete; you want collections.
Putting it all together:
// delete your 'ps' field!
List<String> getKidsNamebyCid(int cid) throws SQLException {
var out = new ArrayList<String>();
String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";
try (PreparedStatement ps = connect.prepareStatement(qry)) {
ps.setInt(1, cid);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) out.add(rs.getString("KIDSNAME"));
}
}
return out;
}
*) The PreparedStatement API is extremely unfortunate. The way you interact with a PS is wildly different vs. a Statement (which you should rarely use; you can't add user input to a plain jane Statement), and yet because reasons and history PreparedStatement extends Statement. That means a whole bevy of methods are in PreparedStatements that you should never call. That's unfortunate. There are 2 things to learn here: [1] Java does not break backwards compatibility, even if that means some of the APIs are horrible, and [2] JDBC is not really meant for 'human consumption'. We don't program our CPUs in machine code either, yet machine code exists and will continue to. We use 'machine code' as glue; something library and language developers use as common tongue. So it is with JDBC: It's not meant for you. Use a library with a nice API, like JDBI. This probably goes beyond what your high school curriculum wants, but hey. There's not much to say except: It's on your curriculum and teacher that they're making you work with outmoded tools 'real'** developers don't use.
**) 'real' in the sense of: Is writing code that powers apps that get a lot of dollars and/or eyeballs.
You need to learn how PreparedStatement actually works. I highly recommend you follow a tutorial to learn how to use it, then follow the pattern for your own code.
But it's also all in the documentation, so let be quote the various relevant pieces.
The javadoc of executeQuery() says:
Executes the SQL query in this PreparedStatement object and returns the ResultSet object generated by the query.
The code in the question is already wrong at this point, since it **ignores the return value of the executeQuery() call.
In addition, the javadoc of getResultSet() says:
Retrieves the current result as a ResultSet object. This method should be called only once per result.
The code in the question is even more wrong at this point, since it calls getResultSet() repeatedly in a loop.
If you had read the javadoc of the methods you're using, it would have been obvious that something is wrong. As already stated, going through a tutorial would have shown how to do this right. Actually, any web search for examples of executing a query using JDBC would show that.
For extra background information for how it works, the javadoc of execute() says:
Executes the SQL statement in this PreparedStatement object, which may be any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate.
The execute method returns a boolean to indicate the form of the first result. You must call either the method getResultSet or getUpdateCount to retrieve the result; you must call getMoreResults to move to any subsequent result(s).
The javadoc of getMoreResults() says:
Moves to this Statement object's next result, returns true if it is a ResultSet object, and implicitly closes any current ResultSet object(s) obtained with the method getResultSet.
The "return multiple results" is not talking about multiple rows from a single query, but about multiple results from multiple queries. It generally requires the execution of a stored procedure, or a block of SQL code, for this to happen.
This is how to correctly get the multiple rows from the execution of a single SELECT statement:
String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";
try (PreparedStatement ps = connect.prepareStatement(qry)) {
ps.setInt(1, cid);//setting CID
try (ResultSet rs = ps.executeQuery()) {
int i = 0;
while (rs.next()) {
out[i] = rs.getString("KIDSNAME");
i++;
}
}
}
If the SQL code in question had returned multiple result sets, you would do it this way:
try (PreparedStatement ps = connect.prepareStatement(qry)) {
// call ps.setXxx() methods here
boolean isResultSet = ps.execute();
while (isResultSet) {
try (ResultSet rs = ps.getResultSet()) {
int i = 0;
while (rs.next()) {
// call rs.getXxx() methods here
i++;
}
}
isResultSet = ps.getMoreResults();
}
}
That is better written using for loops, to keep the loop logic together:
try (PreparedStatement ps = connect.prepareStatement(qry)) {
// call ps.setXxx() methods here
for (boolean isResultSet = ps.execute(); isResultSet; isResultSet = ps.getMoreResults()) {
try (ResultSet rs = ps.getResultSet()) {
for (int i = 0; rs.next(); i++) {
// call rs.getXxx() methods here
}
}
}
}

Getting affected row count when there is no resultset object

I have given a pl/sql procedure that I am supposed to call from java code through jdbc.
public boolean deleteCompany(TimeStamp timestamp, Long companyId){
String str = "{call Delete_Company(?,?)}";
CallableStatement statement = null;
boolean deleted = false;
try{
statement = conn.prepareCall(str);
statement.setLong(1,companyId);
statement.setTimestamp(2,timeStamp);
statement.execute();
deleted = true;
return deleted;
}finally{
statement.close();
}
}
The problem is even if I send the wrong id number it obviously executes statement so varaible deleted becomes true. I tried .executeUpdate() method to be able to get affected row counts but it did not work properly cause when in both cases(when deletion/no deletion happened) it retrieved 1. I suppose the problem is the pl/sql procedure I am using just performs delete operation but not retrieve any result set object. So neither executeUpdate() nor getUpdateCount() methods does not help me. My question is there any way I can get affected row counts even if I have no result set object?
FYI: I understand that affected row count could be sent as a out parameter from pl/sql procedure, but I have no authority to make any change on the db side.
Since you can't change the stored procedure, one solution is to do the following
Get the number of rows before calling an update operation (select count(*) from your_tbl where .....)
Delete the records as you're already doing
Get the number of rows after the delete action and check if the number of affected rows is the same as in #1 (num_rows#1 - num_rows#3)
Other transactions can still make this approach somewhat unreliable because they can also change your table between steps #1 and #3.
If that's a concern for you, then you should use transactions (just place your Java code in a transaction).
Your statement.execute(); returns a boolean value and it always return true if the execution is success irrespective of what the procedure is doing on call. Further you can refer the below code for what you are looking.
...
boolean hadResults = cStmt.execute();
//
// Process all returned result sets
//
while (hadResults) {
ResultSet rs = cStmt.getResultSet();
// process result set
...
hadResults = cStmt.getMoreResults();
}
//
// Retrieve output parameters
//
// Connector/J supports both index-based and
// name-based retrieval
//
int outputValue = cStmt.getInt(2); // index-based
outputValue = cStmt.getInt("inOutParam"); // name-based
...

JDBC PreparedStatement Query

I'm working on JDBC with Oracle database.
I have the below methods:
// Method1
public void method1(){
Connection connection=ConnectionFactory.getRemoteConnection();
selectSQL = "select * tablename where num>=? and num<=?";
PreparedStatement userStatement=connection.prepareStatement(selectSQL);
userStatement.setFetchSize(500);
int i=0;
int startRow=0;
int endRow=50;
do{
// Reusing the statement
fetchRecords(userStatement,startRow,endRow);
startRow=startRow+50;
endRow=endRow+50;
i++;
if(i==50) endOfRows=true;
}while(!endOfRows);
userStatement.close();
}
// Method2
public List<String> fetchRecords(PreparedStatement userStatement,int startRow,int endRow){
userStatement.setInt(1, startRow);
userStatement.setInt(2, endRow);
resultSet = userStatement.executeQuery();
/*Some logic*/
...
}
As you can see, I'm trying to reuse a prepared statement.
Now, my question is while a prepared statement be created everytime I change parameters?
I'm closing the statement only after the end of all the processing in method1.
I'm worried if a new statement is created everytime I change the parameters (since I'm not closing all of them), it may end up in un-closed statement.
Should I be worried?
Thank you,
Sash
java.sql.PreparedStatement is designed to be reusable.
When you set new parameters, you will overwrite the previous ones but you will not create a new Statement.
You can also decide to clear all the parameters yourself using clearParameters()

How to assign resultSet to global variable to use output of one method in another method in java

I am trying to store the output value of one method in a global variable so that i can use that value in another method. I code in java with play framework.
I have method where i need to run a query and the query is a dynamic one it is generated based on the filter conditions from user request.
I wish to save the resultSet in the first method so that i can use that resultSet data in the next method.
resultSet queryData;
public String list() {
connection = "";
resultSet data;
query ="";
data = this.Execute(query,connection);
return "data";
}
public byte[] dataList() {
connection = "";
while(queryData.next()){
xyz;
}
}
This is a sample of my code i have similar to this.
In my first method the query is executed and the resultSet is assigned to variable data.
I would like to store it in queryData global variable and use that in the next method.
Is there a way to do so?
Pls help
If your local variable data in list method is returned, then I don't understand why you need global variable to store it? You can call it in your next method, and store it in a local variable there??
For example:
public ResultSet list() {
connection = "";
ResultSet data;
query ="";
data = this.Execute(query,connection);
return data;
}
public byte[] dataList() {
ResultSet data = list();
connection = "";
while(data.next()){
xyz;
}
}

Use of getters in ResultSets

I am trying to write java code to access a table 'customer' with columns 'customer_id', 'email', 'deliverable', and 'create_date'
I have
Connection conn = DriverManager.getConnection(connectionUrl, connectionUser, connectionPassword);
Statement constat = conn.createStatement();
String query = "SELECT * FROM customer WHERE customer_id LIKE " + customerId;
ResultSet rtn = constat.executeQuery(query);
Customer cust = new Customer(rtn.getInt("customer_id"), rtn.getString("email"), rtn.getInt("deliverable"), rtn.getString("create_date"));
conn.close();
return cust;
I am receiving the error:
java.sql.SQLException: Before start of result set
As far as I can tell, my error is in the line where I am creating a new Customer object, but I cannot figure out what I am doing wrong. Can anyone offer me some help? Thanks!
You must always go to the next row by calling resultSet.next() (and checking it returns true), before accessing the data of the row:
Customer cust = null;
if (rtn.next()) {
cust = new Customer(rtn.getInt("customer_id"),
rtn.getString("email"),
rtn.getInt("deliverable"),
rtn.getString("create_date"));
}
Note that you should also
use prepared statements instead of String concatenation to avoid SQL injection attacks, and have more robust code
close the connections, statements and resultsets in a finally block, or use the try-with-resources construct if using Java 7
Read the JDBC tutorial
You should call ResultSet.first() to move the result to the first position. The result set is a programming convention not to retrieve the whole result of the query and keep in memory. As such, its interface is quite low level and you must explicit select the row via methods like first(), last() or next() (each returns true to check if the requested row index is in the set)
You need to add
rtn.next();
before you use the result set.
Usually this is done as
while (rtn.next()) {
<do something with the row>
}

Categories