I have the below class with 3 resultsets.
public class AllMetricsResultSet {
ResultSet top10Files;
ResultSet top10FilesForUsage;
ResultSet top10DataSet;
}
In another method, I have 3 different select statements(I've given only one select below, but there are 3) which assign result sets into the above.
public AllMetricsResultSet SPDataList (String alldata)
{
...........
String sSQL = "SELECT USERNAME, NUMBEROFFILES FROM FILE_INFO";
PreparedStatement stm = dbConnection.prepareStatement(sSQL);
if (stm.execute())
//TopTenantsForUsage = stm.getResultSet();
rs.top10Files = stm.getResultSet();
rs.top10FilesForUsage = stm.getResultSet();
rs.top10DataSet = stm.getResultSet()
Then finally from another method, I am calling the previous method as follows:
AllMetricsResultSet mrs = SPDataList(alldata);
while (mrs.top10Files.next())
(This while statement fails. I see that there are 10 rows returned. I tried mrs.top10Files.getFetchSize() (this also failed)
Any help would be greatly appreciated.
It's not a good practice to execute the queries in one method and read data from the result sets in a different method.
You want to finish your DB access as quick as possible and close the connection, in order to return the connection to the connection pool (relevant when you have multiple threads accessing the db) and release any db locks your statements may require.
Therefore the result set variables shouldn't br instance variables at all. You should create and consume them in the same method.
You could have, though, a separate method for each of your 3 queries, and each of them can return the data it fetched.
Instead try like this
public AllMetricsResultSet SPDataList (String alldata) {
String sSQL1 = "query1";
String sSQL2 = "query2";
String sSQL3 = "query3";
try {
PreparedStatement stm1 = dbConnection.prepareStatement(sSQL1);
PreparedStatement stm2 = dbConnection.prepareStatement(sSQL2);
PreparedStatement stm3 = dbConnection.prepareStatement(sSQL3);
if (stm1.execute())
top10Files = stm1.getResultSet();
if (stm2.execute())
top10FilesForUsage = stm2.getResultSet();
if (stm3.execute())
top10DataSet = stm3.getResultSet();
while (top10Files.next()) {
//get the resultset1 data
}
while (top10FilesForUsage.next()) {
//get the resultset2 data
}
while (top10DataSet.next()) {
//get the resultset3 data
}
// dont know why as you want to return the classType
//create an object of the class initialize it the the data you obtained
//and return it
}
catch(SQLException e)
{
e.printStackTrace();
}
finally {
//resultsetobject close
//statementObject close
//connection object close
}
}
Related
I'm trying to my a very simple webapplication, webshop, for cupcakes.
From the webApp you can choose a cupcake form the dropdown with three attributes
(top, bottom, quantity). These are stored in an ArrayList on my sessionScope but all in numbers e.g. Chokolate as 1 and Vanilla as 2. I want to use these topId numbers to ask my DB (MySQL) for what is in 1 and then have it return Chokolate.
I think I am almost there with my code, but can't get it to return my String, as my topId is an Int.
public static Top getTopById(int topId) {
readFromArrayPutInSQL();
String sql = "INSERT INTO cupcaketopping (toppingType, toppingPrice) VALUES (?, ?)";
try {
ConnectionPool connectionPool = new ConnectionPool();
String query = "SELECT toppingType FROM cupcaketopping";
Statement statement = connectionPool.getConnection().createStatement();
ResultSet rs = statement.executeQuery(query);
rs.getString(topId);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return topId; //Here is the problem - I GUESS?
}
Code after changes due to input in comments, seem to be working!
public static Top getTopById(int topId) {
readFromArrayPutInSQL();
String query = "SELECT toppingType FROM cupcaketopping WHERE toppingID = "+topId+"";
try {
ConnectionPool connectionPool = new ConnectionPool();
PreparedStatement preparedStatement = connectionPool.getConnection().prepareStatement(query);
ResultSet rs = preparedStatement.executeQuery(query);
rs.next();
return new Top(rs.getString(1));
//connectionPool.close(); //NOTE! Won't run, IntelliJ is asking me to delete!
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
There are a few problems:
You're selecting all rows from the cupcaketopping table, regardless of the topId. You should probably be using a PreparedStatement, and then use topId as part of your query.
You never call ResultSet#next(). The result set always starts "before" the first row. You have to call next() for each row in the result set (it returns true if there is a row to read).
The ResultSet#getString(int) method gets the String value of the column at the given index of the result. You only select one column, so the argument should probably be 1 (not topId).
You never close the Statement when done with it.
Depending on how your connection pool class works, you might actually need to close the Connection instead.
You never try to use the String returned by rs.getString(topId).
You never try to convert the query result to a Top instance.
Given it's possible the query will return no result, you might want to consider making the return type Optional<Top>.
The sql string seems to have no purpose.
Your code should look more like this:
public Optional<Top> getTopById(int topId) {
Connection conn = ...;
String query = "SELECT toppingType FROM cupcaketopping WHERE id = ?";
// closes the statement via try-with-resources
try (PreparedStatement stat = conn.prepareStatement(query)) {
stat.setInt(1, topId);
ResultSet rs = stat.executeQuery();
// assume unique result (as it's assumed the ID is the primary key)
if (rs.next()) {
// assumes 'Top' has a constructor that takes a 'String'
return Optional.of(new Top(rs.getString(1)));
} else {
return Optional.empty();
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
Your actual implementation may vary, depending on how the rest of your code is designed.
public ResultSet getAllCustomer() throws SQLException{
//List L = new ArrayList();
try {
stm = con.prepareStatement("select * from customer");
resultSetSubject = stm.executeQuery();
while (resultSetCustomer.next()) {
//L.add(resultSetCustomer);
resultSetCustomer.getInt(1);
resultSetCustomer.getString(2);
//System.out.println(resultSetCustomer.getInt("id")+" "+resultSetCustomer.getString("name"));
}
} catch (Exception e) {
System.out.println(e);
}
return resultSetCustomer;
}
Let me brief, I am fetching all record from the customer table and returning as resultset. I am accessing returned resultset as
ResultSet rs = T.getAllCustomer();
System.out.println(rs.getInt("id")+" "+rs.getString("name"));
There are several issues in your code:
You are obtaining a ResultSet object, looping over all of the rows in it, getting the column values, and then returning this ResultSet object. By the time it is returned to the caller, it has already been consumed by the loop that processed the rows (this is the cause of the error in your question).
Don't return the ResultSet object, instead create a Customer entity class that maps to the data in the DB, and return an instance of Customer. Returning a ResultSet object is really bad as it doesn't give control over how the object is closed, nor does it make your code object-oriented.
You don't need to create a prepared statement if you don't have a parameterized query.
The Statement (and ResultSet) must be closed after done. You should wrap the code that processes the whole result in a try-with-resources statement.
Your code needed little amendment
1 > Ensure resultset variable you use are same as defined (one place its different in your code).
2> use only
public ResultSet getAllCustomer() throws SQLException{
try {
stm = con.prepareStatement("select * from customer");
resultSetCustomer = stm.executeQuery();
} catch (Exception e) {
System.out.println(e);
}
return resultSetCustomer;
}
3> Close your connection/resultset/statement in separate method otherwise you will get error. you can use as below
public void close() throws SQLException{
if (resultSetCustomer != null) {
resultSetCustomer .close();
}
if (stm !=null) {
stm.close();
}
}
4> use resultset(your resultset instance).next() while accessing
I have a loop in my code. It iterates over the result set. Whenever the value of qc = 0, it should update a table in the database.
But it is only updating the database table only for the first time it comes across qc = 0. And then it just comes out of the while loop. It does not go for the next iteration to check for another value of "qc"
String sql5 = "select t$pdno ,t$opno, t$qcmp , t$qtbf from ttisfc010100 where t$pdno = "+pdno+" and t$opno <= "+opno ;
ResultSet getData3 = db.getStmt().executeQuery(sql5);
while(getData3.next()) {
int pd , op , qc , qt ;
pd = getData3.getInt(1);
op = getData3.getInt(2);
qc = getData3.getInt(3);
qt = getData3.getInt(4);
String sql7="";
if(qc==0)
{
sql7 = "update ttisfc010100 set t$qcmp = "+quantity+" , t$qtbf = "+quantity+" where t$pdno = "+pd+" and t$opno = "+op;
db.getStmt().executeUpdate(sql7);
}
}
catch (SQLException e) {
e.printStackTrace(); }
The getStmt() method contains the logic to create a normal statement . See below :
public class DatabaseConnection
{
Statement stmt;
public void openConnection() {
Class.forName(classForName);
conn = DriverManager.getConnection(driver+dsn, user, password);
stmt = conn.createStatement();
}
public Statement getStmt()
{
if(stmt==null)
{
stmt = this.getNewStmt();
}
return stmt;
}
public Statement getNewStmt() {
Statement newStmt;
try {
newStmt = conn.createStatement();
}
catch(Exception e){
newStmt = stmt;
}
return newStmt;
}
I have removed the usage of Normal statement , and used a prepared statement in my code . Now that solved my problem .
Thanks a lot . You people are awesome.
The problem is that you reuse the same Statement to execute your second query in the loop. When you execute a new query on the same Statement object, any previously opened statements on that same object are closed, including their result sets.
I am a bit surprised that you don't receive a SQLException that the result set is closed.
Also note that a class like your DatabaseConnection is a bit weird, as it makes correctly managing JDBC resources harder, not easier.
I'm developing a web application in which users can insert a number of "products". These products will be inserted in a MySQL database. I have a problem when I try to retrieve data from a table of my database. Here is my method:
public ArrayList<Product> getProductByAppId(int appId) {
ArrayList<Product> list = new ArrayList<Product>();
String query = "select prodId from app_prod where appId = ?";
try {
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, appId);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Product item = getProductById(resultSet.getInt("prodId"));
list.add(item);
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
This method simply gets an int as a parameter and retrieves from the table app_prod all the objects I have stored. The method getProductById it's an helper method and it works properly. When I try to debug my code, I see that I enter in the while cycle only once! So all I see is the very first element in my DB, but I have more than a single product in my DB.
To make things shorter, I've omitted methods to open and close connection because they work properly.
I think the error is something very obvious, but I can't really see it.
OK the problem is the following:
resultSet is declared as a global variable and is being used by both methods.
When the second method changes its contents and gets through it by :
resultSet.next();
And reaches the end of it:
The main outer loop tries to do resultSet.next(), it directly exits from the loop since it had already reached its end beforehand in the getProductById method.
List<Product> list = new ArrayList<>();
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setInt(1, appId);
try (resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
Product item = getProductById(resultSet.getInt("prodId"));
list.add(item);
}
return list;
}
} catch (Exception e) {
e.printStackTrace();
}
The try-with-resources ensure that statement and resultset are closed (even despite the return).
Also now the variables are local. And that might be the problem: maybe you reused those global fields in getProductById. resultSet would be my guess. (Pardon me.)
I have following code:
public boolean updateDatabase(long houseValue, List<Users> userList)
{
boolean result = false;
Connection conn = null;
PreparedStatement stmtUpdateUsers = null;
PreparedStatement stmtQueryHouse = null;
PreparedStatement stmtUpdateHouse = null;
ResultSet rs = null;
String updateUsers = "UPDATE users SET money = ? WHERE username = ?";
String queryHouse = "SELECT * FROM house WHERE house_id = ?";
String updateHouse = "UPDATE house SET house_money = ? WHERE house_id = ?";
try
{
conn = getConnectionPool().getConnection();
conn.setAutoCommit(false);
stmtUpdateUsers = conn.prepareStatement(updateUsers);
...
// Here is some code that updates Users table in a short loop
...
stmtQueryHouse = conn.prepareStatement(queryHouse);
stmtQueryHouse.setInt(1, 1);
rs = stmtQueryHouse.executeQuery();
if(rs.next())
{
long houseMoney = rs.getLong("house_money");
houseMoney += houseValue;
stmtUpdateHouse = conn.prepareStatement(updateHouse);
stmtUpdateHouse.setLong(1, houseMoney);
stmtUpdateHouse.setInt(2, 1);
stmtUpdateHouse.executeUpdate();
}
else
{
throw new SQLException("Failed to update house: unable to query house table");
}
conn.commit();
result = true;
}
catch(SQLException e)
{
logger.warn(getStackTrace(e));
try{conn.rollback();}catch(SQLException excep)
{
logger.warn(getStackTrace(excep));
}
}
finally
{
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(stmtQueryHouse);
DbUtils.closeQuietly(stmtUpdateUsers);
DbUtils.closeQuietly(stmtUpdateHouse);
try { conn.setAutoCommit(true); } catch (SQLException e) { /* quiet */ }
DbUtils.closeQuietly(conn);
}
return result
}
This method can be called from multiple threads, house table is just a one row table which holds total earned money. It gets updated by different threads.
Problem is that stmtQueryHouse.executeQuery() returns empty set, and it should not happen, because house table always have (since database creation) one single row that gets updated (only house_money column is updated).
When I run this code on windows (JDBC driver + mysql 5.5.13) it works fine, but when I run it on CentOS (same JDBC driver + mysql 5.1.57) it returns empty result set very often (if not always). Any idea what is going wrong or how could I check where is the problem? Maybe I should use select for update, but then why it works on windows and not on linux? I appreciate any help. Thanks in advance.
Look in the mysql general query log for any errors?
I realize this isnt your question per se, but if you have another table with just a single row for each House, it sounds to me that it would make more sense to move house_money into your main house table
I'd say this one method is doing far too much.
I'd pass in the Connection to three separate methods and manage the transaction outside all of them.
I'd wonder if there's an optimization that would eliminate one of the UPDATES.
I'd want to batch all these so I didn't do a round trip for each and every user. It'll perform poorly as the # of users increases.