This question already has answers here:
Why does my ArrayList contain N copies of the last item added to the list?
(5 answers)
Closed 4 years ago.
I tried to print the objects from hashSet collection. the console display only the last object(one object). when I used ArrayList with the same method, I'm able to print all the objects. i've used an iterator method in order to print the collection set, see the attached test.
public Set<Coupon> getAllCoupouns() throws Exception {
Coupon coupon = new Coupon();
Set<Coupon> coupons = new HashSet<Coupon>();
// Open a connection
conn = DriverManager.getConnection(Utils.getDBUrl());
// Define the Execute query
java.sql.Statement stmt = null;
try {
stmt = conn.createStatement();
// build The SQL query
String sql = "SELECT * FROM COUPON";
// Set the results from the database
ResultSet resultSet = stmt.executeQuery(sql);
// constructor the object, retrieve the attributes from the results
while (resultSet.next()) {
coupon.setId(resultSet.getLong(1));
coupon.setTitle(resultSet.getString(2));
coupon.setStartDate((Date) resultSet.getDate(3));
coupon.setEndDate((Date) resultSet.getDate(4));
coupon.setAmount(resultSet.getInt(5));
CouponType type = CouponType.valueOf(resultSet.getString(6)); // Convert String to Enum
coupon.setType(type);
coupon.setMessage(resultSet.getString(7));
coupon.setPrice(resultSet.getDouble(8));
coupon.setImage(resultSet.getString(9));
coupons.add(coupon);
}
} catch (SQLException e) {
throw new Exception("Retriev all the coupons failed");
} finally {
// finally block used to close resources
try {
if (stmt != null)
conn.close();
} catch (SQLException se) {
// do nothing
}
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
return coupons;
}
As you are initialising Coupon from outside the while loop, it keeps adding same object every time and hence, overwriting results in only last result being displayed.
What you need to do is to instantiate Coupon from within the while loop, e.g.:
public Set<Coupon> getAllCoupouns() throws Exception {
Set<Coupon> coupons = new HashSet<Coupon>();
// Open a connection
conn = DriverManager.getConnection(Utils.getDBUrl());
// Define the Execute query
java.sql.Statement stmt = null;
try {
stmt = conn.createStatement();
// build The SQL query
String sql = "SELECT * FROM COUPON";
// Set the results from the database
ResultSet resultSet = stmt.executeQuery(sql);
// constructor the object, retrieve the attributes from the results
while (resultSet.next()) {
Coupon coupon = new Coupon();
coupon.setId(resultSet.getLong(1));
coupon.setTitle(resultSet.getString(2));
coupon.setStartDate((Date) resultSet.getDate(3));
coupon.setEndDate((Date) resultSet.getDate(4));
coupon.setAmount(resultSet.getInt(5));
CouponType type = CouponType.valueOf(resultSet.getString(6)); // Convert String to Enum
coupon.setType(type);
coupon.setMessage(resultSet.getString(7));
coupon.setPrice(resultSet.getDouble(8));
coupon.setImage(resultSet.getString(9));
coupons.add(coupon);
}
} catch (SQLException e) {
throw new Exception("Retriev all the coupons failed");
} finally {
// finally block used to close resources
try {
if (stmt != null)
conn.close();
} catch (SQLException se) {
// do nothing
}
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
return coupons;
}
cupon is always the same object. You make only one object of class Cupon, so the set contains only one object (you add always the same object). You must make a new object in each iteration in the while loop.
Related
I want to insert values for multiple columns of a table. I am doing an Eclipse Project and I want to feed the data from my project into the database. There are multiple columns in the database and I have values for each of these columns from my Eclipse Project. The JDBC driver and the connections are all done. I just need to figure out how to input these values from the project into the table.
public void insert(Double num1, Double num2, Double result) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection con = null;
PreparedStatement stmt = null;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/Calculator", "root", "");
stmt = con.prepareStatement("INSERT INTO RESULT(ID,VALUE1,VALUE2,RESULT) VALUES (?,?,?,?))");
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
}
}
if (con != null) {
try {
con.close();
} catch (SQLException ex) {
}
}
}
}
You're close to an answer, your are missing the setXXX calls to assign values to the ? in your insert statement, you didn't provide a value for ID in your function parameter and you have an extra parenthesis in the prepareStatement.
stmt = con.prepareStatement("INSERT INTO RESULT(ID,VALUE1,VALUE2,RESULT) VALUES (?,?,?,?)");
// stmt.set___(1,___);
stmt.setDouble(2,num1);
stmt.setDouble(3,num2);
stmt.setDouble(4,result);
I have the following class:
public class Refunds {
ResultSet dataToHash = null;
public Refunds (String UrnId) {
Database db = null;
CallableStatement callable;
String query = "select * from testmdb.dbo.ApEdiZcusSaSendFile where SourceID='LAN' and UrnID=?";
// Get database connection
try {
db = new Database("jdbc/refund");
} catch (NamingException | SQLException e1) {
e1.printStackTrace();
}
// Run the query
try {
callable = db.connection.prepareCall(query);
callable.setString(1, UrnId);
dataToHash = callable.executeQuery();
} catch (SQLException s) {
System.out.println("A SQL exception was thrown while running the query: ");
s.printStackTrace();
} catch (Exception e) {
System.out.println("A general exception was thrown while running the query: ");
e.printStackTrace();
} finally {
db.closeConnection();
}
}
public ResultSet getDataToHash() {
return dataToHash;
}
}
And I use it like this:
// Get the result set
Refunds refunds = new Refunds(urnId);
ResultSet dataToHash = refunds.getDataToHash();
However, every single time dataToHash is .closed(). I don't close my ResultSet. Whatever the problem is, how can I modify this code so that when I get it, it won't be closed?
PS - Just ignore my old school System.outs...
You close the connection, and that closes the ResultSet.
Instead of storing the ResultSet in a class member, store it in a local variable inside Refunds, and read all the data from it before returning from the Refunds method and closing the connection.
I am trying to create a method from where I can query my database and retrieve a whole table.
Currently, it works just fine if I use the data inside the method. However, I want the method to return the results.
I'm getting a java.sql.SQLException: Operation not allowed after ResultSet closed on the current code.
How can I achieve this?
public ResultSet select() {
con = null;
st = null;
rs = null;
try {
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery("SELECT * FROM biler");
/*
if (rs.next()) {
System.out.println(rs.getString("model"));
}*/
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
return rs;
}
You should never pass a ResultSet around through public methods. This is prone to resource leaking because you're forced to keep the statement and the connection open. Closing them would implicitly close the result set. But keeping them open would cause them to dangle around and cause the DB to run out of resources when there are too many of them open.
Map it to a collection of Javabeans like so and return it instead:
public List<Biler> list() throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<Biler> bilers = new ArrayList<Biler>();
try {
connection = database.getConnection();
statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
resultSet = statement.executeQuery();
while (resultSet.next()) {
Biler biler = new Biler();
biler.setId(resultSet.getLong("id"));
biler.setName(resultSet.getString("name"));
biler.setValue(resultSet.getInt("value"));
bilers.add(biler);
}
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return bilers;
}
Or, if you're on Java 7 already, just make use of try-with-resources statement which will auto-close those resources:
public List<Biler> list() throws SQLException {
List<Biler> bilers = new ArrayList<Biler>();
try (
Connection connection = database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
ResultSet resultSet = statement.executeQuery();
) {
while (resultSet.next()) {
Biler biler = new Biler();
biler.setId(resultSet.getLong("id"));
biler.setName(resultSet.getString("name"));
biler.setValue(resultSet.getInt("value"));
bilers.add(biler);
}
}
return bilers;
}
By the way, you should not be declaring the Connection, Statement and ResultSet as instance variables at all (major threadsafety problem!), nor be swallowing the SQLException at that point at all (the caller will have no clue that a problem occurred), nor be closing the resources in the same try (if e.g. result set close throws an exception, then statement and connection are still open). All those issues are fixed in the above code snippets.
If you don't know what you want of the ResultSet on retrieving time I suggest mapping the complete thing into a map like this:
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
Map<String, Object> row = null;
ResultSetMetaData metaData = rs.getMetaData();
Integer columnCount = metaData.getColumnCount();
while (rs.next()) {
row = new HashMap<String, Object>();
for (int i = 1; i <= columnCount; i++) {
row.put(metaData.getColumnName(i), rs.getObject(i));
}
resultList.add(row);
}
So basically you have the same thing as the ResultSet then (without the ResultSetMetaData).
Well, you do call rs.close() in your finally-block.
That's basically a good idea, as you should close all your resources (connections, statements, result sets, ...).
But you must close them after you use them.
There are at least three possible solutions:
don't close the resultset (and connection, ...) and require the caller to call a separate "close" method.
This basically means that now the caller needs to remember to call close and doesn't really make things easier.
let the caller pass in a class that gets passed the resultset and call that within your method
This works, but can become slightly verbose, as you'll need a subclass of some interface (possibly as an anonymous inner class) for each block of code you want to execute on the resultset.
The interface looked like this:
public interface ResultSetConsumer<T> {
public T consume(ResultSet rs);
}
and your select method looked like this:
public <T> List<T> select(String query, ResultSetConsumer<T> consumer) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery(query);
List<T> result = new ArrayList<T>();
while (rs.next()) {
result.add(consumer.consume(rs));
}
} catch (SQLException ex) {
// logging
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
return rs;
}
do all the work inside the select method and return some List as a result.
This is probably the most widely used one: iterate over the resultset and convert the data into custom data in your own DTOs and return those.
As everyone before me said its a bad idea to pass the result set. If you are using Connection pool library like c3p0 then you can safely user CachedRowSet and its implementation CachedRowSetImpl. Using this you can close the connection. It will only use connection when required. Here is snippet from the java doc:
A CachedRowSet object is a disconnected rowset, which means that it makes use of a connection to its data source only briefly. It connects to its data source while it is reading data to populate itself with rows and again while it is propagating changes back to its underlying data source. The rest of the time, a CachedRowSet object is disconnected, including while its data is being modified. Being disconnected makes a RowSet object much leaner and therefore much easier to pass to another component. For example, a disconnected RowSet object can be serialized and passed over the wire to a thin client such as a personal digital assistant (PDA).
Here is the code snippet for querying and returning ResultSet:
public ResultSet getContent(String queryStr) {
Connection conn = null;
Statement stmt = null;
ResultSet resultSet = null;
CachedRowSetImpl crs = null;
try {
Connection conn = dataSource.getConnection();
stmt = conn.createStatement();
resultSet = stmt.executeQuery(queryStr);
crs = new CachedRowSetImpl();
crs.populate(resultSet);
} catch (SQLException e) {
throw new IllegalStateException("Unable to execute query: " + queryStr, e);
}finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
LOGGER.error("Ignored", e);
}
}
return crs;
}
Here is the snippet for creating data source using c3p0:
ComboPooledDataSource cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("<driver class>"); //loads the jdbc driver
} catch (PropertyVetoException e) {
e.printStackTrace();
return;
}
cpds.setJdbcUrl("jdbc:<url>");
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);
javax.sql.DataSource dataSource = cpds;
You can use the CachedRowSet object that is just for what you want:
public CachedRowSetImpl select(String url, String user, String password) {
CachedRowSetImpl crs = null;
try (Connection con = DriverManager.getConnection(url, user, password);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM biler");) {
crs = new CachedRowSetImpl();
crs.populate(rs);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
return crs;
}
You can read the documentation here:
https://docs.oracle.com/javase/7/docs/api/javax/sql/rowset/CachedRowSet.html
You're closing the ResultSet and consequently you can't use it anymore.
In order to return the contents of the table, you'll have to iterate through the ResultSet and build a per-row representation (in a List, perhaps?). Presumably each row represents some entity, and I would create such an entity for each row.
while (rs.next()) {
list.add(new Entity(rs));
}
return list;
The alternative is to provide some callback object, and your ResultSet iteration would call on that object for each ResultSet row. That way you don't need to build an object representing the whole table (which may be a problem if it's sizable)
while (rs.next()) {
client.processResultSet(rs);
}
I would be reluctant to let clients close the result set/statement/connection. These need to be managed carefully to avoid resource leaks, and you're much better off handling this in one place (preferably close to where you open them!).
Note: You can use Apache Commons DbUtils.closeQuietly() to simply and reliably close the connect/statement/resultset tuple (handling nulls and exceptions properly)
It is bad practice to return result set ,secondly you are already closing it so after closing it you can not use it anymore.
I would suggest using Java 7 with multiple resource in try block will helpful you as suggested above.
If you want entire table result ,you should return its output rather than resultSet.
Assuming you can afford storing the entire result in memory, you may simply return some table-like structure. Using Tablesaw for instance, simply do
Table t = Table.read().db(rows);
with rows a standard java.sql.ResultSet. For details see here. Tablesaw becomes especially useful if you intend to slice-and-dice your data further as it gives you Pandas-like functionality.
There are many steps involved in executing one SQL statement in Java:
Create connection
Create statement
Execute statement, create resultset
Close resultset
Close statement
Close connection
At each of these steps SQLException can be thrown. If we to handle all exception and release all the resources correctly, the code will will look like this with 4 levels of TRY stacked on the top of each other.
try {
Connection connection = dataSource.getConnection();
try {
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM myTable");
try {
ResultSet result = statement.executeQuery();
try {
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
finally {
result.close();
}
}
finally {
statement.close();
}
}
finally {
connection.close();
}
}
catch (SQLException e) {
// Handle exception
}
Can you propose a better (shorter) way to execute a statement while still release all the consumed resources?
If you are using Java 7, the try with resources statement will shorten this quite a bit, and make it more maintainable:
try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(queryString); ResultSet rs = ps.execute()) {
} catch (SQLException e) {
//Log the error somehow
}
Note that closing the connection closes all associated Statements and ResultSets.
Check out Apache Commons DbUtils, and in particular the closeQuietly() method. It will handle the connection/statement/result set closing correctly, including the cases where one or more are null.
An alternative is Spring JdbcTemplate, which abstracts a lot of work away from you, and you handle your database queries in a much more functional fashion. You simply provide a class as a callback to be called on for every row of a ResultSet. It'll handle iteration, exception handling and the correct closing of resources.
I create a utility class with static methods I can call:
package persistence;
// add imports.
public final class DatabaseUtils {
// similar for the others Connection and Statement
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (Exception e) {
LOGGER.error("Failed to close ResultSet", e);
}
}
}
So your code would be:
Integer theOne = null;
Connection connection = null;
PreparedStatement statment = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
while (result.next()) {
theOne = result.getInt(1);
}
} catch (SQLException e) {
// do something
} finally {
DatabaseUtils.close(result);
DatabaseUtils.close(statement);
DatabaseUtils.close(connection);
}
return theOne;
I'd recommend instantiating the Connection outside this method and passing it in. You can handle transactions better that way.
Connection connection = null;
PreparedStatement statement = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
catch (SQLException e) { /* log error */ }
finally {
if (result != null) try { result.close(); } catch (Exception e) {/*log error or ignore*/}
if (statement != null) try { statement.close(); } catch (Exception e) {/*log error or ignore*/}
if (connection != null) try { connection.close(); } catch (Exception e) {/*log error or ignore*/}
}
Just close the Connection, this releases all resources*. You don't need to close Statement and ResultSet.
*just make sure you don't have any active transactions.
Your code can be shortened and written in this way...
Connection connection = dataSource.getConnection();
PreparedStatement statement = null;
ResultSet result = null;
try {
statement= connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
} catch (SQLException e) {
// Handle exception
} finally {
if(result != null) result.close();
if(statement != null) statement.close();
if(connection != null) connection.close();
}
Can someone help me with this: I'm making a java database application and I want to put my methods for select,insert,update and delete into separated class so they can be called from another classes and reused.
Till now I managed to separate only methods for update and delete and for insert when not using prepared statement. Problem I'm encountering is how to return data's when doing select from database and put them into table.
Here are my update and delete method's in Queries class:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.Konekcija.Konekcija;
public class Queries {
Konekcija konekcija = new Konekcija();
public void updateTable(String sqlQuery){
Connection conn = null;
Statement st = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
st.executeUpdate(sqlQuery);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void deleteFromTable(String sqlQuery){
Connection conn = null;
Statement st = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
st.executeUpdate(sqlQuery);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
P.S. Connection properties are in another class "Konekcija"
You should create a collection and populate it with the results of the query, it should look something like:
List<Foo> selectFoos(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement("select * from foo");
try {
ResultSet resultSet = ps.executeQuery();
try {
List<Foo> foos = new ArrayList<Foo>();
while (resultSet.next()) {
Foo foo = new Foo();
// use resultSet methods get... to retrieve data from current row of results
// and populate foo
foos.add(foo);
}
} finally {
resultSet.close();
}
} finally {
ps.close();
}
return foos;
}
try executeQuery method. in the java doc for "resultset" class you will find a example:
http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html
Return data for "select from table" would be ResultSet.
You may return the ResultSet to caller and get values (or)
Inside the "Select" method of Queries class retrieve the data from resultset and set it some VO object and add this VO to collection and return the collection (assuming you will get more than one row in ResultSet). For example if you are querying User table, create Java bean class "User" with get/set methods. Set retrieved values to this bean and return it.
//Create User class with get/set in some package.
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
ResultSet rs=st.execute(sqlQuery);
//Instantiate user class
while (rs.next())
System.out.println("Name= " + rs.getString("moviename") + " Date= " + String fName = rs.getString("firstName");
User myUser = new User();
myUser.setFirstName(fName);
}
NOTE: This code is hand typed. There may be syntax errors. Please use it as starting point.