Java JDBC select records - java

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.

Related

how to merge two different resultsets from two different DBs in java

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.

Java mysql query ("SELECT * FROM movies" is only returning 1 row

I´m doing a simple movie-renting application, and this method from the DAO section is supposed to return an array of "movie" objects, but only returns 1 movie.
I checked the database, connection is fine, but only list the first row and nothing else. There are currently 3 movies entries on the database.
public ArrayList<Pelicula> obtainMovies () {
ArrayList<Movie> p=new ArrayList<>();
Movie pelic=new Movie();
try{
conn=connect();
String sql="SELECT * FROM movies";
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
if(rs.next()){
pelic.setTitle(rs.getString("title"));
pelic.setGenre(rs.getString("genre"));
pelic.setRating(rs.getInt("rating"));
pelic.setRented(rs.getBoolean("rented"));
p.add(pelic);
}
else {return null;}
return p;
}
Assuming your table has more then one row, this
if(rs.next()){
should use a loop like
while(rs.next()){
Also, you'll need to add more then one instance to your List, so move pelic into the loop body
while(rs.next()){
Movie pelic=new Movie();
Or you'll add only one instance of Movie to the List (and modify that single instance with each loop iteration).
if(rs.next()){
You probably want to loop over all results:
while(rs.next()){

ResultSet reset when using recursion

I have a question regarding ResultSet objects in Java and recursion.
I was working on some code for university and whenever I found a descendant I recursed on with that new node but when I came out of the recursion and tried to rs.next() the pointer had gone from pointing to row 1 back to row 0 and when it hit row 0 the rs.next() failed and it returned! I knew there was one thing in there that it hadn't read yet! What is it that causes this?
The only way I got round that problem was to go through the resultset and get every element and add it into an array list, then loop through the arraylist doing the recursion on each element in the array! Surely this must be a better way around this?
This is the new code I'm using
private Vector<String> getDescendents(String dogname, Vector<String> anc) {
if (anc == null) anc = new Vector<String>();
ArrayList<String> tempList = new ArrayList<String>(2);
try {
System.out.println("Inside ");
childStmt.setString(1,dogname);
childStmt.setString(2,dogname);
ResultSet rs = childStmt.executeQuery();
System.out.println("Before while "+rs.getRow());
while (rs.next()){
String col1 = rs.getString(1);
tempList.add(col1);
anc.add(col1);
}
for (String s:tempList){
getDescendents(s,anc);
}
}
catch(Exception e) {
doError(e, "Failed to execute ancestor query in getBreeding");
}
return anc;
}
However before this, I had the getDescendents call inside the while loop and thus no for loop and no arraylist either, but whenever it actually recursed it would loose track of the resultset when it returned out of the recursion.
Further details :
When I used the debugger (nearly said gdb there lol far too much C) the ID of the result set was the same but the row pointer had returned to 0 and the rs.next call failed!
Once again any explanation is appreciated!
p.s it previously looked like
private Vector<String> getDescendents(String dogname, Vector<String> anc) {
if (anc == null) anc = new Vector<String>();
ArrayList<String> tempList = new ArrayList<String>(2);
try {
System.out.println("Inside ");
childStmt.setString(1,dogname);
childStmt.setString(2,dogname);
ResultSet rs = childStmt.executeQuery();
System.out.println("Before while "+rs.getRow());
while (rs.next()){
String col1 = rs.getString(1);
anc.add(col1);
getDescendendts(col1,anc);
}
}
catch(Exception e) {
doError(e, "Failed to execute ancestor query in getBreeding");
}
return anc;
}
It looks like you're re-using childStmt; don't do this. From the Statement javadoc:
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.
You'll have to either save all the rows first, then do the recursive query, or create a new Statement for each ResultSet you want to fetch.

Total Number of Row Resultset getRow Method

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...

How can I have a Java method return multiple values?

I was just wondering whether there's a way to make a Java method return multiple values.
I'm creating an application that uses the jdbc library to work with a database. I can successfully enter values into the database but I need a way to return them, and this is where I'm a bit stuck. I creating a form into which the user enters a specific value (an ID number) which is then passed to by Database class which carries out my database work.
Database newQuery = new Database();
newQuery.getCust(c_ID); //uses the GetCust method in my class,
//passing it the ID of the customer.
The getCust() method in my Database class creates the following query:
ResultSet Customer = stat.executeQuery("SELECT * FROM Persons WHERE Cust_ID=C_ID");
I need a way to return the results that are stored in Customer back. Any ideas?
Why not just return Customer, or create a small class with all the values you want returned in it and return that class?
You can't exactly return multiple values from a method in Java, but you can always return a container object that holds several values. In your case, the easiest thing to do would be to return the ResultSet, Customer.
If you're concerned about exposing your data layer to your UI, you can copy the data from the ResultSet into a structure that is less specific to the database, either a List of Maps, or perhaps a List of Customer objects, where Custom is a new class that represents your business entity.
So your actual problem is that you didn't know how to set values/parameters in a SQL query? The only right way to do this is using PreparedStatement.
String sql = "select * from Customers where Cust_ID = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setLong(custId);
resultSet = preparedStatement.executeQuery();
It not only eases setting Java objects (String, Long, Integer, Date, InputStream and so on) in a SQL query, but most importantingly it will save you from SQL Injection risks. Further it's also faster than a Statement because it's precompiled.
As to your code logic, you should always close the DB resources in the reverse order in the finally block to avoid resource leaks in case of exceptions. Here's a basic example how to obtain a Customer the right JDBC way:
public Customer find(Long customerId) throws SQLException {
String sql = "SELECT id, name, age FROM customer WHERE id = ?";
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Customer customer = null;
try {
connection = getConnectionSomehow();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setLong(custId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
customer = new Customer();
customer.setId(resultSet.getLong("id"));
customer.setName(resultSet.getString("name"));
customer.setAge(resultSet.getInteger("age"));
}
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (preparedStatement != null) try { preparedStatement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return customer;
}
You may find this tutorial useful to get more insights and examples.
Each customer could be accompanied with a little interface that describes a method that takes multiple arguments. You then pass in the object that implements this interface to have the result delivered to it.
The object that implement it can of course be the same as the method calling getCustomer belongs to, so it just passes a reference to 'this' and assign the arguments to fields that you can expect to have been set when it all returns.
Consider using an object/relational mapping library. It will handle the details of packaging the multiple data values you need to return from the JDBC ResultSet into a single Java bean object.
Which one to pick is another discussion. A lot of smart people use Hibernate. The Java platform includes JPA. Using one off the shelf will save you from inventing your own, which is what devising your own combination of objects and collections would end up being.
In addition to using Hibernate - take a look at Spring. It supports connection pooling etc and allows you to abstract the JDBC away from your code completely.
It will either return you a List of Maps or a List of your custom type (depending on how you call it).

Categories

Resources