1

I am just getting started with jsp and my question is this - when I have a singleton class, how do I tidy up after it?

In particular:

public class DBConnection {
  private static Connection connection = null;
  private static Statement statement = null;

  public static ResultSet executeQuery(String query){
    if (connection == null) { /*initConnection*/ }
    if (statement == null) { /*initStatement*/ }

    // do some stuff
  }
}

Now, I use this class in several pages to get results from jdbc. However, I need to eventually call statement.close(); and connection.close(); - when should I call those?

I am using singleton, because it felt wrong to call for connection to a database over and over whenever I needed to make a query.

Martin Melka
  • 7,177
  • 16
  • 79
  • 138

3 Answers3

1

The Connection must be closed always, and after you have executed all your database statements for the desired operations. Two examples:

Case 1: You must show a list of products to user filtered by criteria from database. Solution: get a connection, retrieve a list of products using the filter criteria, close the connection.

Case 2: The client selects some of these products and updates the minimum stock to get an alert and restock them. Solution: get a connection, update all the products, close the connection.

Based on these cases, we can learn lot of things:

  • You can execute more than a single statement while having/maintaining a single connection open.
  • The connection should live only in the block where it is used. It should not live before or after that.
  • Both cases can happen at the same time since they are in a multi threaded environment. So, a single database connection must not be available to be used by two threads at the same time, in order to avoid result problems. For example, user A searches the products that are in category Foo and user B searches the products that are in category Bar, you don't want to show the products in category Bar to user A.
  • From last sentence, each database operation ((or group of similar operations like Case 2) should be handled in an atomic operation. To assure this, the connection must not be stored in a singleton object, instead it must be live only in the method being used.

In consequence:

  • Do not declare the Connection nor the Statement nor the ResultSet nor other JDBC resource as static. It will simply fail. Instead, declare only the Connection as field of your DBConnection class. Let each method decide to handle each Statement (or PreparedStatement) and ResultSet and specific JDBC resources.
  • Since you must close the connection after its usage, then add two more methods: void open() and void close(). These methods will handle the database connection retrieval and closing that connection.
  • Additional, since the DBConnection looks like a wrapper class for Connection class and database connection operations, I would recommend to have at least three more methods: void setAutoCommit(boolean autoCommit), void commit() and void rollback(). These methods will be plain wrappers for Connection#setAutoCommit Connection#close and Connection#rollback respectively.

Then you can use the class in this way:

public List<Product> getProducts(String categoryName) {
    String sql = "SELECT id, name FROM Product WHERE categoryName = ?";
    List<Product> productList = new ArrayList<Product>();
    DBConnection dbConnection = new DBConnection();
    try {
        dbConnection.open();
        ResultSet resultSet = dbConnection.executeSelect(sql, categoryName); //execute select and apply parameters
        //fill productList...
    } catch (Exception e) {
        //always handle your exceptions
        ...
    } finally {
        //don't forget to also close other resources here like ResultSet...
        //always close the connection
        dbConnection.close();
    }
}

Note that in this example the PreparedStatement is not in the getProducts method, it will be a local variable of the executeSelect method.

Additional notes:

  • When working in an application server, you should not open connections naively e.g. using Class.forName("..."), instead use a database connection pool. You can roll on some database connection pooling libraries like C3P0 as explained here: How to establish a connection pool in JDBC?. Or configure one in your application server, as I explain here: Is it a good idea to put jdbc connection code in servlet class?
  • If this is for learning purposes, then roll on your own classes to handle the communication with your database. In real world applications, this is not recommended (doesn't mean you should not do it). Instead, use a database connectivity framework like ORMs e.g. JPA (Java official ORM framework) or Hibernate; there are no ORM frameworks that handles database communication like Spring JDBC and MyBatis. The choice is yours.

More info:

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • Thank you for this very thorough explanation. One question though. Is it reasonable to have a static class providing methods such as `public static Flight getFlightByID(int flightID);` ? This method would instantiate DBConnection, connect, do its queries, and then close, as you suggested. The said static class does not have any member variables, it only provides its methods. – Martin Melka Oct 17 '13 at 08:23
  • @MartinMelka no, it is not. In fact, you should avoid using singletons at all. – Luiggi Mendoza Oct 17 '13 at 14:16
1

Define connection resource in mywebapp/META-INF/context.xml file

<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource" 
    maxActive="10" maxIdle="2" maxWait="20000" 
    driverClassName="com.mysql.jdbc.Driver" 
    username="myuser" password="mypwd" 
    url="jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=utf8"
    validationQuery="SELECT 1" />

Create DB.java helper class to minimize code in other parts of app

import java.sql.*;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;

public class DB {

public static Connection createConnection() throws SQLException {
    try {
        Context ctx = new InitialContext();
        DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mydb");
        return ds.getConnection();
    } catch (SQLException ex) {
        throw ex;
    } catch (Exception ex) {
        SQLException sqex = new SQLException(ex.getMessage());
        sqex.initCause(ex);
        throw sqex;
    }
}

public static void close(ResultSet rs, Statement stmt, Connection conn) {
       if (rs != null) try { rs.close(); } catch (Exception e) { }
       if (stmt != null) try { stmt.close(); } catch (Exception e) { }
       if (conn != null) try { conn.close(); } catch (Exception e) { }
}

public static void close(ResultSet rs, boolean closeStmtAndConn) {
       if (rs==null) return;
       try {
          Statement stmt = rs.getStatement();
          close(rs, stmt, stmt!=null ? stmt.getConnection() : null);
       } catch (Exception ex) { }
}

}

And somewhere in your app DAO code use DB helper.

public List<MyBean> getBeans() throws SQLException {
    List<MyBean> list = new ArrayList<MyBean>();
    ResultSet rs=null;
    try {
        Connection con = DB.createConnection();
        String sql = "Select * from beantable where typeid=?";
        PreparedStatement stmt = con.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
        stmt.setInt(1, 101);
        rs = stmt.executeQuery();
        while(rs.next()
            list.add( createBean(rs) );
    } finally {
        DB.close(rs, true); // or DB.close(rs, stmt, conn);
    }
    return list;
}

private MyBean createBean(ResultSet rs) throws SQLException {
    MyBean bean = new MyBean();
    bean.setId( rs.getLong("id") );
    bean.setName( rs.getString("name" );
    bean.setTypeId( rs.getInt("typeid") );
    return bean;
}
Whome
  • 10,181
  • 6
  • 53
  • 65
0

I would add two methods to the class:

public static void open() throws SomeException;
public static void close() throws SomeException;

then your calling code looks something like this{

try {
    DBConnection.open();
    ... code to use the connection one or more times ...
} finally {
    DBConnection.close();
}

Wrap all your database calls inside that and it will take care of closing whether there is an exception thrown or not.

Of course, this isn't much different than having a regular class, which I might recommend:

try {
    DBConnection conn = new DBConnection();
    conn.open();

    ... all the code to use the database (but you pass 'conn' around) ...

} finally {
    conn.close();
}

And you might want to look at the java.lang.AutoCloseable and java.io.Closeable to see if that helps you.

2

If you are keeping it open across page loads, there isn't any place to put the try ... finally stuff so you can open it and close it when the servlet closes or the server closes or something like that.

If you are going to leave it open, you need to make sure and add code to verify it doesn't close when you aren't looking. A short network glitch, for example, could close it down. In that case, you need to reopen it when it gets closed. Otherwise, all database access from that point will fail.

You might want to look into the concept of a DataBase Pool. Apache has one -- DBCP. Tomcat has its own that's quite good. Other containers, like JBOSS, WebSphere, WebLogic all have them. There's a couple that can be used with the Spring Framework. What it does is manage one or more database connections. Your code asks it for one and it returns an open one, unless none is available and then it opens one and returns it. You call close when your code gets through with it but it doesn't really close the connection, it just returns it to the pool.

You can usually configure the pool to check for shut down connections and reopen if needed.

Lee Meador
  • 12,829
  • 2
  • 36
  • 42
  • That is true, if it was used only in the said block. However, I have several pages, from which I do my queries through the same DBConnection that remains opened. I don't think it is good to connect and disconnect to the database on *each* page load. Or is it? – Martin Melka Oct 16 '13 at 19:14
  • There's a huge problem here that is handling the connection state in a singleton. This is plain wrong =\ – Luiggi Mendoza Oct 16 '13 at 19:46
  • Tomcat or any j2ee provides connection pool so calling conn.close() does not actually close it but puts back to a pool for reuse. Pool handles broken connections, limit max open connection etc.. boiler stuff. Its very lightweight using conns from the pool. And no two threads should access same connection instance at the same time, it will happen if you use static singletons. – Whome Oct 16 '13 at 20:07
  • @Whome even when using a database connection pool, you must call `Connection#cllose` to return the connection to the pool and let it handle the connection behavior. When you don't call this method, the connection is still open and the application will have performance leaks. – Luiggi Mendoza Oct 17 '13 at 14:15
  • @LuiggiMendoza Right. You DO have to close. But you can call close after each small access to the database and the pool keeps things open to the database server over the long term. – Lee Meador Oct 17 '13 at 17:33
  • @LeeMeador leave that work and problems to the connection pool, after all, that's what it was made for. – Luiggi Mendoza Oct 17 '13 at 17:34
  • @LuiggiMendoza I much prefer your solution to the problem but its not what the OP asked. What was asked was how to close connections when using a static class. Neither of us really answered that question though I tried to show how it could be done in my first section. Solutions to this problem have come a long way since the 1900s but newcomers haven't seen how poor the older solutions are. I stand by my main point about making sure to close what you open and the secondary point about using a pool. – Lee Meador Oct 17 '13 at 17:40
  • @LeeMeador the solution is: stop having the connection in a static class for several reasons and start using it locally. After doing this, you can close the connection after using it. All this is covered in my answer, but maybe it is not clear. – Luiggi Mendoza Oct 17 '13 at 17:42
  • @LuiggiMendoza I guess we disagree on the "how" of answering this question which was "when I have a singleton class, how do I tidy up after it?" We do not disagree on how best to do database access in this situation. – Lee Meador Oct 17 '13 at 17:43
  • 1
    The question is how to close connections in a singleton class in a multithreaded environment, from the title: *Singleton In JSP*, and web applications are by default multithreaded. The first step to solve this **in these environments** is to understand why is **bad** to store the connection in a singleton object. For example, two requests fire at the same time and try to execute different `SELECT` statements, but one of them finishes early than the other; since they're using the same `Connection` object, then the one that finished first would close it and the other operation will break. – Luiggi Mendoza Oct 17 '13 at 17:52
  • After realizing this, the solution pops up immediately: **do not use a singleton object for `Connection` in multithreaded environments**. – Luiggi Mendoza Oct 17 '13 at 17:53