Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Here is my story. I have myCon=getUnusedConnection(); method that get a connection from Connection pool. I also have a releaseConnection(myCon); method to release Connection to the pool after finishing using it.
Ok, When coding, I need to select data from Database many times & cos I wanna reuse my code so I wanna have many methods for 1 single Action. Ex,
public static List<String[]> getData(){
Connection myCon=null;
PreparedStatement preparedStmt=null;
try{
myCon=getUnusedConnection();
String sql="select ........";
preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
String str="";
if(results.next()){
str=results.getString(1);
}
if(!str.equals("")){
List<String[]> list=getData2(myCon, preparedStmt, str);
}
return list;
}
catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally{
releaseConnection (myCon);
closeStatement (preparedStmt);
}
return null;
}
public static List<String[]> getData2(Connection myCon, PreparedStatement preparedStmt, String str){
try{
List<String[]> list=new ArrayList<String[]>();
String sql="c.......";
preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
while(results.next()){
list.add(results.getString(1));
}
return list;
}catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally {
closeStatement(preparedStmt);
releaseConnection(myCon);
}
return null;
}
Do i need to include try - catch - finally in getData2?
Since I am passing myCon & prepareStatement around so I am not sure is this the right way to code.
Is it a standard way for what I am coding? or do u do better coding?
Do i need to include try - catch - finally in getData2?
The answer depends on other places from which you call getData2:
If getData is the only place, then the answer is "no", a try/finally would be sufficient.
If there are other places all of which expect a SQLException and process it in the same way, the answer is also "no", for the same reason (no catch is required).
If there are other places, some of which do not expect SQLException, then you need to keep the try - catch - finally
However, there is a problem with the way that you coded your call of getData2: since getData2 has a finally that releases the connection, your getData releases the connection twice. You need to either add a useExistingConnection(conn) and modify your releaseConnection in a way to count references to the same connection, or pass a flag that indicates whether or not the connection should be closed.
Generally, I would prefer to structure the code to open and close the connection in the same method, pass the connection around to other methods, and use try/finally only to close the PreparedStatements opened inside subordinate methods, such as getData2.
I'd made your method getData2() private and not catching (if it handle the exception same as parent) and closing resources in finally if you do in top level. If you can't change it, make another method private for example getData3() without try-catch-finally.
However i'd made another change, if all of your methods follow the same template.
The callable interface for calling.
public interface Queryable<T>{
T execute();
}
Then the util class.
public final class SQLUtil {
private SQLUtil() { }
public static Connection getConnection() {
return getUnusedConnection();
}
public <T> static T query(Queryable queryable) {
T toReturn = null;
try {
toReturn = queryable.execute();
} catch (SQLException ex) {
while (ex != null) {
System.err.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
} catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
} finally {
releaseConnection (myCon);
closeStatement (preparedStmt);
}
}
//add code for getUnusedConnection, releaseConnection, closeStatement
}
And yor client code will look like this:
public List<String[]> getData(){
return SQLUtil.query(new Queryable<List<String[]>>() {
#Override
public List<String[]> execute() {
Connection myCon=getUnusedConnection();
String sql="select ........";
PreparedStatement preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
String str="";
if(results.next()) {
str=results.getString(1);
}
List<String[]> list = null;
if(!str.equals("")) {
list=getData2(myCon, preparedStmt, str);
}
return list;
}
});
}
Related
I made the DAO to create a sales offer and it is similar to an other DAO where it makes users and that connects and works. But the one below keeps skipping the if statements and I'm not sure why it isn't adding to the data base. I ran the same command in the SQL string in oracle and it worked there.
public boolean sendOffer(Sales sell) {
boolean done = false;
int key =0;
Connection conn = cu.getConnection();
try {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[]keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foriegn key
ps.setInt(3, sell.getCarID()); // forgien key
int number = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if(number!=1)
{
log.warn("data insert fail");
}
else
{
log.trace("success");
done=true;
}
if(rs.next()) {
key=rs.getInt(1);
sell.setID(key);
conn.commit();
}
else {
log.warn("data not found");
}
}catch(SQLException e)
{
}
finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
// TODO Auto-generated method stub
return done;
}'''
The main issue is that an exception is happening in your code but the try/catch block is intercepting it and swallowing it silently. While it may be tempting to catch and swallow exceptions, truth is it always causes more problems than it solves and the key concept of handling exceptions is to NOT handle them: just put the throws declaration and let the application crash.
You then have other possible side-issues depending on how the Connection was obtained in the first place, like the fact that you're never closing the PreparedStatement and the ResultSet (if the connection is closed, they are closed as well... but if the connection is returned to a pool then they are never going to be closed).
In general the above code tends to pack too much functionality in a single method and can quickly spiral out of control, so you might want to divide it in smaller chunks with clear individual responsibilities.
All of the above is common to observe wherever Connection and PreparedStatement are used directly, be it for maximum performance reasons or for lack of experience. Typically in web applications using the Spring framework this is solved through the use of a JdbcTemplate but I cannot assume that you are using Spring so I won't show its usage here.
At a minimum, I would modify your code roughly as follows:
public boolean sendOffer(Sales sell) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = cu.getConnection();
ps = prepareInsertOfferStatement(sell, conn);
ps.executeUpdate();
rs = ps.getGeneratedKeys();
sell.setID(extractKey(rs));
conn.commit();
log.trace("success");
return true;
}
catch(Exception ex) {
log.error(ex); // this is actually probably bad. Consider putting a throws declaration and get rid of this catch
return false;
}
finally {
closeQuietly(rs, ps, conn);
}
}
private void closeQuietly(AutoCloseable... objs) {
for(AutoCloseable obj : objs) {
try {
obj.close();
} catch (SQLException e) {
// this is usually mostly safe to ignore. Maybe log a warning somewhere
}
}
}
private PreparedStatement prepareInsertOfferStatement(Sales sell, Connection conn) throws SQLException {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[] keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foreign key
ps.setInt(3, sell.getCarID()); // foreign key
return ps;
}
private int extractKey(ResultSet rs) throws SQLException {
if(rs.next()) {
return rs.getInt(1);
}
else {
throw new Exception("The statement did not return any generated key.");
}
}
As you can see it's not shorter, but responsibilities are clearer and all objects are closed accordingly. Furthermore, it gives you nice reusable primitives to close connections and related objects and to extract the key from other inserts you will want to do. Further abstractions would allow you to obtain more primitives, but I think this is sufficient for you to get the gist of it.
I have some methods that follow this pattern
try(Connection connection = MySqlConnection.getConnection()){
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
...
statement.executeUpdate();
...
}
catch(SQLException e) {
throw new RuntimeException(e);
}
I was told to extract try-catch with connection to class MySqlConnection and create a new method that would execute all logic and encapsulate creating connection. So, I don't quite get this approach and have no idea, how to resolve it without writing some ugly templates or strategies. Would it be better to just leave it as it is, or can it be implemented in an easy way?
Create a ConnectionHelper that will deal with exceptions. This is a little bit tricky, you have to define your own functional interface because standard Consumer does not work with checked SQLExceptions:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public void doSomeUpdate() {
ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
statement.executeUpdate();
});
}
This works well as long as you don't have to return anything from your database, which is rarely the case. So we need to extend the helper with another functional interface, ConnectionFunction, to be used when an object needs to be returned:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
...
}
#FunctionalInterface
public interface ConnectionFunction<T> {
T apply(Connection connection) throws SQLException;
}
public static <T> T doWithConnection(ConnectionFunction<T> connectionFunction) {
try (Connection connection = MySqlConnection.getConnection()) {
return connectionFunction.apply(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public boolean doSomeQuery() {
return ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement("SELECT * FROM table");
return statement.execute();
});
}
Updates
2 solutions to work with SQLIntegrityConstraintViolationException:
Own, runtime exception:
As this is a runtime exception, you just add try-catch where needed.
public static class MySQLIntegrityConstraintViolationException extends RuntimeException {
public MySQLIntegrityConstraintViolationException(Throwable cause) {
super(cause);
}
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw new MySQLIntegrityConstraintViolationException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
insertWithConnection:
A specialized version of doWithConnection(). Again, use it only where/when applicable.
public static void insertWithConnection(ConnectionConsumer connectionConsumer) throws SQLIntegrityConstraintViolationException {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw e;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Use java functional interface to separate exception handling from business logic, like this:
public class ExceptionHandler() {
public R execute(Function<T,R> function, T argument) {
try {
return function.apply(argument)
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Now you can pass to the class above any function that will contain your logic and handling exception will be independent.
Furthermore, this way you can create many useful methods, and classes that work like a proxy, or which are needed for every operation, and hat will be independent of your business logic.
For example, in the same way, you can write:
your own transaction management,
logging input and output
check user and permissions
and any other interceptor
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
What is the return type for this program?
I don't know what return type must be given to the following program. It is used to send multiple rows at the same time.
public class TimeSheetDao {
public static final String sql= "insert into logintable values(?,?,?,?,?,?,?,?,?,?)";
public static int insert(List<EmployeeBean> ebList) throws Exception {
PreparedStatement ps=null;
System.out.println("In TimesheetDao");
Connection conn=ConnectionProvider.getConn();
System.out.println("before sql");
System.out.println("after sql");
ps = conn.prepareStatement(sql);
try {
System.out.println(" in try in Timesheetdao");
conn.setAutoCommit(false);
for (EmployeeBean logintable: ebList){
ps.setString(1,logintable.getEmpid());
ps.setDate(2,new Date(logintable.getLogindate().getTime()));
ps.setString(3,logintable.getLogintime());
ps.setString(4,logintable.getLogouttime());
ps.setString(5,logintable.getLunch());
ps.setString(6,logintable.getAfterlunchlogin());
ps.setString(7,logintable.getAfterlunchlogout());
ps.setString(8,logintable.getTask());
ps.setString(9,logintable.getTotal());
ps.setString(10,logintable.getOvertime());
ps.addBatch();
}
int i[]= ps.executeBatch();
conn.commit();
}
catch (SQLException e) {
System.out.println(e.getMessage());
conn.rollback();
}
finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// What should I return here ?
return ?;
}
}
I know the return type should be of int type. but the array of int i[]=ps.executeBatch(); cannot be returned so i dont know.
In order to get you started, read what the docs have to say about the meaning of i's contents:
an array of update counts containing one element
for each command in the batch.
The elements of the array are ordered according to the order
in which commands were added to the batch.
As you are submitting one command per EmployeeBean in your method's ebList parameter, you may want to return the sum over i.
However, the only definite answer can be given by your class design !
The return type should be int (Integer). You can see this in public static int... declaration
I would return boolean, true for successful insert, false for failure.
public static boolean insert(List<EmployeeBean> ebList) throws Exception {
...
try{
...
int i[]= ps.executeBatch();
conn.commit();
return true;
}
catch (SQLException e) {
System.out.println(e.getMessage());
conn.rollback();
return false;
}
finally {
...
}
}
I have different methods, which queries different data from a database, but the main structure of every method is the same. To reduce the code, I want to shrink that but I don't know how. I have tried interfaces but the return statement cannot called from an inner class. (It should be typesafe!)
Structure:
public <special type> getXYdata(some parameters) {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(... special query ...)
) {
// Handle ResultsSet and return object of a special type.
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Idea:
private interface QHandler<T> {
String getQuery();
T handleResultSet(ResultSet set) throws SQLException;
}
And then:
private void executeQuery(QHandler handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
But if I call this private method in one of my data mathods, I cannot return an object from the handleResultSet() methods, because the return statement will affect this interface method. Is there an option, to tell the execiteQuery() method which return type the handler has?
Attention: It has to be type safe, no casting if possible!
Your method should not use a raw QHandler type, and should be generic:
private <T> T executeQuery(QHandler<T> handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
return handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Note that you're trying to reinvent Spring's JdbcTemplate. You might consider using it instead of reinventing it.
Maybe you are open for alternative solutions. If you are using Java 8, you can do somehting like this:
Interface MyHandler {
<T> T handle(Connection c);
}
class MyHelperClass {
public <T> T withConnection(MyHandler handler) {
try {
Connection connection = mDataSource.getConnection();
return handler.handle(connection);
} catch (...) {
...
} finally {
...
}
}
}
Usage:
Result r = myHelperObject.withConnection(con -> {
ResultSet results = connection.createStatement().executeQuery(query)
return new Result(..)
});
This way you can use lambda expressions so you do not need to implement various new classes for your handler interface.
I am getting result set is already closed where i am passing resultset into other method.where should i closed result set.
public void mainTest(){
ResultSet rs= pstmt.executeQuery(query);
List list = populateRS(rs);
if(rs!=null)rs.close();
}
public List populateRS(ResultSet rs){
//work with result set
if(rs!=null)rs.close();
}
You should probably use a try-finally block to close the ResultSet even if populateRS (or something else) throws an exception:
ResultSet rs;
try {
rs = pstmt.executeQuery(query);
List list = populateRS(rs);
} finally {
if (rs != null) {
rs.close();
}
}
Close in the same method you open in if at all possible. Consistently doing this makes it easy for code-reviewers and maintainers to easily triage resources into (obviously freed, obviously problematic, and needs more attention).
A few other notes:
Use try (...) or do the closing in finally so the resource is closed even when the code using it fails with an exception.
Use the #WillClose and #WillNotClose annotations as appropriate so that IDEs and tools like findbugs can point out problems.
public void mainTest(){
List<?> list;
try (ResultSet rs = pstmt.executeQuery(query)) {
list = populateRS(rs);
}
// work with list
}
public List<?> populateRS(#WillNotClose ResultSet rs){
//work with result set
}
or if you're stuck with older Java:
public void mainTest(){
List<?> list;
ResultSet rs = pstmt.executeQuery(query);
try {
list = populateRS(rs);
} finally {
if(rs!=null)rs.close();
}
// work with list
}
Use the new try-with-resources statement which would automatically close the ResultSet whether an exception occurs or not because it implements AutoCloseable.
The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement.
public void mainTest()
{
try (ResultSet rs = pstmt.executeQuery(query)) {
List list = populateRS(rs);
} catch (SQLException ex) {
}
}
public List populateRS(ResultSet rs){
// work with result set
}
It is good to close where you are opening .
It is good programming practise to close all resouces in finally block
public void mainTest()
{
ResultSet rs = null;
try{
rs= pstmt.executeQuery(query);
List list = populateRS(rs);
}finally{
try {
rs.close();
} catch (SQLException ex) {
}
}
}
public List populateRS(ResultSet rs){
//work with result set
}
according to java docs
Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Close things near where you open them. In this case that would be in the mainTest method after you call populateRS. If a method doesn't open something, it shouldn't close it.
You should close the ResultSet in the mainTest method to segregate populateRS method's participation in the lifecycle of the ResultSet.
You should have a finally block in which you should close the ResultSet. This practice gives you a guarantee that the ResultSet is closed even if an exception is thrown.