I have two resultsets, one from DB2 and one from Sybase.
I want to merge these resultsets based on some condition,for which i have made one function which will take two resultsets and merge them.
But i am getting SQL exception- Resultset Closed
I am using Connection object and Prepared statement to connect to the respective DB and execute the query.
public void ExecuteDB2Query(SQLQuery){
Connection DB2con = DB2Sess.connection();
PreparedStatement statement = DB2con.prepareStatement(SQLQuery);
MyResulset1= statement.executeQuery();
}
Another method:
public void ExecuteSybaseQuery(SQLQuery){
Connection Sybasecon = SybaseSess.connection();
PreparedStatement statement = Sybasecon.prepareStatement(SQLQuery);
MyResulset2= statement.executeQuery();
}
Final merge method
puble void merge{
while(MyResultset1.next()){
while(MyResultset2.next()){
<some code here>
}
Do we have any way by which i can loop through these two result sets? without any exception.
It looks like you are trying to loop through those two result sets with a nested loop. That can't be done, since after the inner loop finished its first iteration, MyResultset2 cannot be used anymore.
I suggest you iterate over the two result sets separately and store their data in some Collections. Then you can iterate over those Collections however you like.
Ok, i'll give you your code check it.
public void ExecuteDB2Query(SQLQuery){
Connection DB2con = DB2Sess.connection();
PreparedStatement statement = DB2con.prepareStatement(SQLQuery,ResultSet.TYPE_SCROLL_INSENSITIVE);
myResulset1 = statement.executeQuery();
}
public void ExecuteSybaseQuery(SQLQuery){
Connection Sybasecon = SybaseSess.connection();
PreparedStatement statement = Sybasecon.prepareStatement(SQLQuery,ResultSet.TYPE_SCROLL_INSENSITIVE);
myResulset2 = statement.executeQuery();
}
public void merge{
while(myResultset1.next()){
myResultset2.first();
while(myResultset2.next()){
<some code here>
}
}
}
make changes in this code according to your requirement.
Related
I'm working on a little project and right now I have a problem. I need to search in my database all movies which have same genre. I wrote this function for this thing, but doesn't work so well. In principle I want for each result found to create a new object named Movie and to return him. I tested my function but I have two movies with same gerne and he return me only one object. And my question is why doesn't return me all objects? He should to return all my objects.
public Movie extraction(String Genre)throws SQLException{
Statement stmt=con.createStatement();
ResultSet rs=stmt.executeQuery("select * from movies where genre='"+Genre+"'");
while(rs.next()){
String name=rs.getString("name");
String genre=rs.getString("genre");
int year=rs.getInt("year");
int metascore=rs.getInt("metascore");
System.out.println(name);
return new Movie(name,genre,year,metascore);
}
return null;
}
The problem here is that you return within the loop instead of adding the results to a List and returning that list when the loop completes.
There are several other issues with the code which are not related to your problem but may create problems in the future:
You create a statement and a resultset and never close them.
You are using string concatenation to generate the query instead of a PreparedStatement. If the string Genere is received from some untrusted user (for example in a web application) that user may use SQL injection to transform the query into whatever he wants.
A better solution (warning: untested) is something like the following:
List<Movie> movies = new ArrayList<>();
try(PreparedStatement stmt= con.prepareStament("select * from movies where genre=?")) {
stmt.setString(1, Genere);
try(ResultSet rs = stmt.executeQuery()) {
while(rs.next()){
String name=rs.getString("name");
String genre=rs.getString("genre");
int year=rs.getInt("year");
int metascore=rs.getInt("metascore");
movies.add(new Movie(name,genre,year,metascore));
}
}
}
return movies;
the try statement (called "try with resources") ensures that the statement and the resultset .close methods are called when the block ends.
I'm currently using the Datastax Cassandra driver for Cassandra 2 to execute cql3. This works correctly. I started using PreparedStatement's:
Session session = sessionProvider.getSession();
try {
PreparedStatement ps = session.prepare(cql);
ResultSet rs = session.execute(ps.bind(objects));
if (irsr != null) {
irsr.read(rs);
}
}
Sometimes I get a warning from the driver in my log:
Re-preparing already prepared query . Please note that preparing the same query more than once is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once.
This warning makes sense, but i'm not sure how i should reuse the PreparedStatement?
Should I just create all my PreparedStatement in a constructor/init method and than simply use them?
But does this go well when multiple threads use the same PreparedStatement at the same time (especially calling PreparedStatement.bind() to bind objects)
You may just initialize the PreparedStatement once and cache it while the app is running. It should be available for use as long as the Cassandra cluster is up.
Using the statement from multiple threads is fine (as long as you don't modify it throught setXXX() methods). When you call bind(), the code underneath only reads the PreparedStatement and then creates a new instance of BoundStatement() which the caller thread is then free to mutate.
Here is the source code, if you're curious (search for bind()).
We are using cassandra in a webapplication with Spring. In our case we create the PreparedStatements when the bean which encapsulate the operation against on cf (our repository) is instatiated.
Here you have a snippet of the code we are using:
#Repository
public class StatsRepositoryImpl implements StatsRepository {
#SuppressWarnings("unused")
#PostConstruct
private void initStatements(){
if (cassandraSession == null){
LOG.error("Cassandra 2.0 not available");
} else {
GETSTATS_BY_PROJECT = cassandraSession.prepare(SELECTSTATS+" WHERE projectid = ?");
}
}
#Override
public Stats findByProject(Project project) {
Stats stats = null;
BoundStatement boundStatement = new BoundStatement(GETSTATS_BY_PROJECT);
ResultSet rs = cassandraSession.execute(boundStatement.bind(project.getId()));
for (Row row : rs){
stats = mapRowToStats(row);
}
return stats;
}
By this way the prepared statements are reused each time we execute the method findByProject.
The above solution will work in case the key space is fixed. In case of multi-tenant scenario, this solution will not suffice. I simply did in the following way, where keyspace is passed as a argument.
Check for keyspace from the prepared statement, if it is same as passed argument then do not prepare the statement as it is already prepared in this case.
private BatchStatement eventBatch(List<SomeEvent> events, String keySpace) {
BatchStatement batch = new BatchStatement();
String preparedStmtKeySpace = propEventPer == null? "" : propEventPer.getQueryKeyspace();
if(!keySpace.equals("\"" + preparedStmtKeySpace + "\"")) {
eventStmt = cassandraOperations.getSession().prepare(colFamilyInsert(keySpace + "." + "table_name"));
}
....
private RegularStatement colFamilyInsert(String colFamilyName) {
return insertInto(colFamilyName)
.value(PERSON_ID, bindMarker())
.value(DAY, bindMarker());
}
03-Apr-2017 10:02:24,120 WARN [com.datastax.driver.core.Cluster] (cluster1-worker-2851) Re-preparing already prepared query is generally an anti-pattern and will likely affect performance. Consider preparing the statement only once. Query='select * from xxxx where cjpid=? and cjpsnapshotid =?'
Create a pool of PreparedStatement objects, one for each CQL query.
Then, when these queries are being requested by client, fetch the respective cached PS object and supply values by calling bind().
as explained by Daniel, bind() does new BoundStmt(param) which makes this thread safe.
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
Im new in java and SQL, Im repeating a problem that i don't know how to avoid it:
assume i want to make two executeQuery, one inside the other in the getRequestsFromDB method i make the first executeQuery and in the second method isProfessionalHasThatProfession i make the second executeQuery:
private Vector<ClientRequest> getRequestsFromDB() throws SQLException {
Vector<ClientRequest> retVal = new Vector<ClientRequest>();
ResultSet result = null;
try {
for (int i=0 ; i<_userBean.getProfession().length ; ++i ){
result = _statement.executeQuery("SELECT * FROM "+_dbName+"."+CLIENTS_REQUEST_TABLE+" WHERE "+CLIENTS_REQUEST_T_PROFESSION+"='"+_userBean.getProfession()[i]+"'");
while(result.next()){ //HERE IN THE SECOND LOOP GETTING NULL EXCEPTION
if(isProfessionalHasThatProfession(result.getString(CLIENTS_REQUEST_T_PROFESSION))){
retVal.add(cr);
ClientRequest cr = new ClientRequest
(result.getString(CLIENTS_REQUEST_T_CLIENT_ID),
result.getString(CLIENTS_REQUEST_T_CITY),
result.getString(CLIENTS_REQUEST_T_DATE),
result.getString(CLIENTS_REQUEST_T_PROFESSION));
}
}
}
} catch (SQLException ex) {
throw ex;
}
return retVal;
}
the second function:
private boolean isProfessionalHasThatProfession(String profession) throws SQLException {
ResultSet result = null;
try {
result = _statement.executeQuery("SELECT "+WORKER_PROFESSIONS_T_PROFESSION+" FROM "+_dbName+"."+WORKER_PROFESSIONS_TABLE+" WHERE "+WORKER_PROFESSIONS_T_PROFESSIONAL_ID+"='"+_userBean.getProId()+"'");
while(result.next()){
if(result.getString(1).equals(profession)){
return true;
}
}
} catch (SQLException ex) {
throw ex;
}
return false;
}
in the second loop im getting a SQLException: "operation not allowed after ResultSet closed", i have tried:
close in finally the result with result.close() but also i get exception null pointer exception.
i'm really don't know how to deal with that, ideas?
Thank You!
youre reusing _statement (which i assume is global?) to get 2 different ResultSets, but then you return to the 1st ResultSet (in the outside function) after you got the 2nd (inside the inner function, which automatically closed the 1st) - try using 2 separate statements
Check this link :http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Statement.html
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
And you are reusing your statement
See this quote, from the ResultSet API:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
Looks like you are using a class, or global, scope Statement (_statement), which backs both the resultset you are trying to iterate over, and query details of some sort for each entry in the resultset in your isProfessionalHasThatProfession method. but when you execute a new query with the same Statement, your old ResultSet is closed.
So, you'll need a separate statement for the second query.
From the Java API:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects.
So you have to generate a new Statement for the second ResultSet. Please don't forget to close the Statements respectively.
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...