I am currently reworking an ADF Fusion application, that uses a lot of Java nested in Beans to actually manage JDBC requests. As the code ermerged from the pre-Java8 era there is a bunch of deprecated technologies in it and I neither have the time nor the knowledge to rework everything (which describes the percentage of the code that is outdated and hard to debug).
Something very regularly is that inside the backing bean classes manual JDBC requests with our inhouse DB are handled (often uncannily nested in other methods). As I began to outsource them I realized I wrote the same block of code over and over again:
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = CC.getConn(); //CC is of type "CustomConnection",
//a static assist class that fetches the connection
stmt = conn.createStatement();
rs = stmt.executeQuery("Some SQL");
while(rs.next()) {
//handle the result
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch(Exception e){
e.printStackTrace();
}
}
or for PreparedStatement respectively:
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = CC.getConn(); //CC is of type "CustomConnection",
//a static assist class that fetches the connection
pstmt = conn.prepareStatement("Some SQL");
//populate the pstmt with params
rs = pstmt.executeUpdate();
while(rs.next()) {
//handle the result
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch(Exception e){
e.printStackTrace();
}
}
While I'm aware that this is not the best practice it worked reliable so far but writing multiple methods like this with real difference only in the handling of the ResultSet became very tedious. So my approach was to write an abstract superclass that provides a request() method and let the extending classes define the parameters to populate a PreparedStatement and the handling of the ResultSet.
public abstract class Requestable {
public void request(String SQL, HashMap<String, Integer> args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = CC.getConn();
pstmt = conn.prepareStatement(SQL);
pstmt = fill(args);
onResponse(pstmt.executeUpdate());
//handle result
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
public abstract PreparedStatement fill(HashMap args);
public abstract void onResponse(ResultSet rs);
public Requestable() {
super();
}
}
This would be an example for PreparedStatement. Statements would get an own separate method.
Writing this draft, I came across the issue that some classes which are intended to extend Requestable currently have multiple different requests that they perform (which all need a specific handling of the result). With my approach, I could define the methods fill() and onResponse() only once per class. Is there a way to like pass a function reference to request() that gets defined in the extending class and executed at the position of fill() and onResponse()?
Related
What I did wrong? I tried to swap rs.close(), pstmt.close(), conn.close().
I created a PreparedStatement.
But I still can not display the contents of a database table. If I remove conn.close(), everything works! How close the connection and get an output on the jsp?
This is my code:
public ResultSet executeFetchQuery(String sql) {
ResultSet rs = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = Database.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException ex) {
Logger.getLogger(PhoneDAO.class.getName()).log(Level.SEVERE, null, ex);
}
}
return rs;
}
public ArrayList<Phone> getAllPhone() {
ArrayList<Phone> list = new ArrayList<>();
String sql = "SELECT * FROM phones.product;";
ResultSet rs = executeFetchQuery(sql);
try {
while (rs.next()) {
Phone phone = new Phone();
phone.setId(rs.getInt("id"));
phone.setName(rs.getString("name"));
phone.setPrice(rs.getInt("price"));
phone.setQuantity(rs.getInt("quantity"));
phone.setDescription(rs.getString("description"));
System.err.println(phone);
list.add(phone);
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
return list;
}
ResultSet rs = executeFetchQuery(sql);
The above statement closes everything.
Actually your code should be
DBConnection
Iterate through result set
Store the values/display the value directly(depends on your need)
Finally close the connection.
Which is the proper way to access the data from db.
The more common pattern for this kind of process is to maintain the connection and the statement outside the main query code. This is priomarily because connections would generally be allocated from a pool as they are expensive to create and preparing the same statement more than once is wasteful.
Something like this is most likely to work both efficiently and correctly.
static final Connection conn = Database.getConnection();
static final String sql = "SELECT * FROM phones.product;";
static final PreparedStatement pstmt = conn.prepareStatement(sql);
public ArrayList<Phone> getAllPhone() {
ArrayList<Phone> list = new ArrayList<>();
ResultSet rs = pstmt.executeQuery();
try {
while (rs.next()) {
Phone phone = new Phone();
phone.setId(rs.getInt("id"));
phone.setName(rs.getString("name"));
phone.setPrice(rs.getInt("price"));
phone.setQuantity(rs.getInt("quantity"));
phone.setDescription(rs.getString("description"));
System.err.println(phone);
list.add(phone);
}
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
rs.close();
}
return list;
}
Note how the ResultSet is closed in a finally block to stop leaks.
There are variations of this pattern which, for example, only create the connection and prepare the statement at the last minute rather than as static final fields like I have here.
I'm curious about best practices when it comes to database interaction. I've been using a pattern that I believe handles making sure all of the appropriate objects are closed when I'm done with them. However, a coworker recently refactored my code with a comment along the lines of, "making sure we always close database objects". I need to know if one pattern is "better" than the other for some reason. Is the pattern that I've been using wrong somehow? Does one pattern have advantages over the other?
The pattern that I've been following:
public void doStuff() {
try {
final Connection connection = this.getConnection();
try {
final PreparedStatement ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?");
try {
ps.setString(1, "asdf");
final ResultSet rs = ps.executeQuery();
try {
// get data from rs
} finally {
rs.close();
}
} finally {
ps.close();
}
} finally {
connection.close();
}
} catch (SQLException e) {
// do something with the error
}
}
The pattern that my coworker modifed my code to:
public void doStuff() {
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = this.getConnection();
ps = connection.prepareStatement("SELECT COLA, COLB FROM TBL WHERE COLC = ?");
ps.setString(1, "asdf");
rs = ps.executeQuery();
// get data from rs
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// do something with the error
}
}
if (ps!= null) {
try {
ps.close();
} catch (SQLException e) {
// do something with the error
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// do something with the error
}
}
}
}
If you're using Java 6 or prior, then use the latter because it's easier to read and maintain. Note that the latter can be improved with some refactoring to handle the cumbersome try-catch for every call to close method.
If you're using Java 7 or higher, then use try-with-resources:
try (Connection con = ...;
PreparedStatement pstmt = ...) {
pstmt.setXyz(...);
ResultSet rs = pstmt.executeQuery();
//read data from resultset
//and then close it
rs.close();
} catch (Exception e) {
//handle the exception properly...
}
In case you want to make sure about closing the ResultSet, you may use a nested try-with-resources:
try (Connection con = ...;
PreparedStatement pstmt = ...) {
pstmt.setXyz(...);
try(ResultSet rs = pstmt.executeQuery()) {
//read data from resultset
}
} catch (Exception e) {
//handle the exception properly...
}
The latter is easier to read; deep nesting is hard to reason about.
I prefer safe wrappers around closeables, e.g., they do nothing if the closeable is null. This also makes the mainline code easier to read.
Luigi's answer makes the most sense from Java 7 on, of course.
It's often simpler and cleaner to abstract the closure of your database resources to a dedicated manager object, which will contain any NPE's and such that might be thrown.
A pretty well written one exists as part of the open source project, OpenFire:
https://github.com/igniterealtime/Openfire/blob/master/src/java/org/jivesoftware/database/DbConnectionManager.java#L243
Sample helper method from this DbConnectionManager:
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
}
}
So in your finally block you just pass your resources back into your manager, and it handles the ugly logic to test for nulls and catch exceptions, etc.
Like:
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
ps = con.prepareStatement(yourStatement);
rs = ps.executeQuery();
if (rs != null) {
while (rs.next()) {
// do stuff
}
}
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
} finally {
DbConnectionManager.closeConnection(rs, ps, con);
}
Simulating Go's defer statement :D
try(Defer defer = new Defer())
{
Connection connection = ...;
defer.add( connection::close );
....
Path tmpFile = ...;
defer.add( ()->Files.delete(tmpFile) );
....
} // Defer.close() => executing registered actions, from last to first
How Defer is implemented is left as an exercise to readers:)
I have the following code:
public class Main {
public static void main(String[] args) throws SQLException {
try (
Connection conn = DBUtil.getConnection(DBType.HSQLDB);
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery("SELECT * FROM tours");
) {
DBUtil.getConnection();
} catch (SQLException e) {
DBUtil.processException(e);
}
}
}
I use this code to fetch data from a database. My problem is that I'm not allowed to use the Java 1.7 compiler and have to use 1.6.
How can I translate the try-with-resources-code to use with a 1.6 compiler?
What exactly happens in this special try block?
Oracle explains how try-with-resources works here
The TL;DR of it is:
There is no simple way of doing this in Java 1.6. The problem is the absence of the Suppressed field in Exception. You can either ignore that and hardcode what happens when both try AND close throw different exceptions, or create your own Exception sub-hierarchy that has the suppressed field.
In the second case, the link above gives the proper way of doing it:
AutoClose autoClose = new AutoClose();
MyException myException = null;
try {
autoClose.work();
} catch (MyException e) {
myException = e;
throw e;
} finally {
if (myException != null) {
try {
autoClose.close();
} catch (Throwable t) {
myException.addSuppressed(t);
}
} else {
autoClose.close();
}
}
is equivalent to
try (AutoClose autoClose = new AutoClose()) {
autoClose.work();
}
In case you want to make it easier and not create a whole lot of new Exception classes, you will have to decide what to throw in the catch clause inside the finally (t or e).
PS. Dealing with multiple variable declaration in the try is also discussed in the link above. And the amount of code that you need to do it properly is staggering. Most people take shortcuts in Java 1.6 by not coping with exceptions in the finally block and using nullchecks.
I would advise usage of apache's commons-dbutils library which have class DBUtils with close and closeQuietly methods.
The code would look like this:
import org.apache.commons.dbutils.DBUtils;
...
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = myOwnUtil.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery( "SELECT * FROM table" ); // or any other custom query
} catch ( SQLException e ) {
<<handle exception here>>;
} finally {
DBUtils.closeQuietly( conn );
DBUtils.closeQuietly( stmt );
DBUtils.closeQuietly( rs );
// or simply use DBUtils.close( conn, stmt, rs );
}
Note that closeQuietly will throw no exceptions, while close might cast SQLException, so adapt the code to your own use case.
If you want to close streams than you can use apache's commons-io with IOUtils class which also have close and closeQuietly.
Do it like this:
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection(DBType.HSQLDB);
stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = stmt.executeQuery("SELECT * FROM tours");
} catch (SQLException e) {
DBUtil.processException(e);
} finally {
if(conn != null) {
conn.close();
}
if(stmt != null) {
stmt.close();
}
if(rs != null) {
rs.close();
}
}
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.
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.