I currently support a small, small Java application (using only simple JSPs / servlets) that the intern made for internal use by the company, and I am having connection problems.
Sometimes we get errors from nowhere, such as “Application closed” or “Connection closed”, and then the whole application just stops working and the server needs to be restarted.
I don’t have much experience and I don’t have anyone to instruct me or teach me about best practices, design patterns, etc., but I’m sure this is the wrong way to do this. I read about things like DAL, DAO and DTO. Our application does not have any of them.
An entire web application (i.e. servlets) is basically populated with calls similar to the following:
Database db = Database.getInstance(); db.execute("INSERT INTO SomeTable VALUES (a, b, c)"); db.execute("UPDATE SomeTable SET Col = Val");
SELECTs are performed as follows:
ArrayList<Model> results = Model.fetch("SELECT * FROM SomeTable");
Where Model is a class that extends HashMap and is a single row in a table.
This is the code for Database.java and wondered if anyone could point out the obvious things that are wrong (I'm sure there are a lot of them), any quick fixes that can be made, and some best practices resources with database connections / connection.
package classes; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; public final class Database { public static Database getInstance() { if (Database.instance == null) { Database.instance = new Database(); } return Database.instance; } // Returns the results for an SQL SELECT query. public ArrayList<HashMap<String, Object>> fetch(String sql) { ArrayList<HashMap<String, Object>> results = new ArrayList<HashMap<String, Object>>(); try { PreparedStatement stmt = this.connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); ResultSet rs = stmt.executeQuery(); this.doFetch(rs, results); stmt.close(); } catch (SQLException e) { this.handleException(e, sql); } return results; } public ArrayList<HashMap<String, Object>> fetch(String sql, ArrayList<Object> parameters) { ArrayList<HashMap<String, Object>> results = new ArrayList<HashMap<String, Object>>(); try { // Bind parameters to statement. PreparedStatement pstmt = this.connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); for (int i=0; i<parameters.size(); i++) { pstmt.setObject(i+1, parameters.get(i)); } ResultSet rs = pstmt.executeQuery(); this.doFetch(rs, results); pstmt.close(); } catch (SQLException e) { this.handleException(e, sql, parameters); } return results; } public int execute(String sql) { int result = 0; try { Statement stmt = this.connection.createStatement(); result = stmt.executeUpdate(sql); stmt.close(); } catch (SQLException e) { this.handleException(e, sql); } return result; } public int execute(String sql, ArrayList<Object> parameters) { int result = 0; try { PreparedStatement pstmt = this.connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); for (int i=0; i<parameters.size(); i++) { if (parameters.get(i) == null) { pstmt.setNull(i+1, java.sql.Types.INTEGER); } else { pstmt.setObject(i+1, parameters.get(i)); } } result = pstmt.executeUpdate(); pstmt.close(); } catch (SQLException e) { this.handleException(e, sql, parameters); } return result; } public void commit() { try { this.connection.commit(); } catch (SQLException e) { System.out.println("Failed to commit transaction."); } } public Connection getConnection() { return this.connection; } private static Database instance; private static DataSource dataSource = null; private Connection connection; private Database() { this.connect(); this.execute("SET SCHEMA " + Constant.DBSCHEMA); } private void connect() { Connection connection = null; if (dataSource == null) { try { InitialContext initialContext = new InitialContext(); dataSource = (DataSource)initialContext.lookup( Constant.DEPLOYED ? Constant.PROD_JNDINAME : Constant.TEST_JNDINAME); } catch (NamingException e) { e.printStackTrace(); } } try { connection = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } this.connection = connection; } // Fetches the results from the ResultSet into the given ArrayList. private void doFetch(ResultSet rs, ArrayList<HashMap<String, Object>> results) throws SQLException { ResultSetMetaData rsmd = rs.getMetaData(); ArrayList<String> cols = new ArrayList<String>(); int numCols = rsmd.getColumnCount(); for (int i=1; i<=numCols; i++) { cols.add(rsmd.getColumnName(i)); } while (rs.next()) { HashMap<String, Object> result = new HashMap<String, Object>(); for (int i=1; i<=numCols; i++) { result.put(cols.get(i-1), rs.getObject(i)); } results.add(result); } rs.close(); } private void handleException(SQLException e, String sql) { System.out.println("SQLException " + e.getErrorCode() + ": " + e.getMessage()); System.out.println("Statement: " + sql); ExceptionAdapter ea = new ExceptionAdapter(e); ea.setSQLInfo(e, sql); throw ea; } private void handleException(SQLException e, String sql, ArrayList<Object> parameters) { if (parameters.size() < 100) { System.out.println("SQLException " + e.getErrorCode() + ": " + e.getMessage()); System.out.println("PreparedStatement: " + sql.replace("?", "[?]")); System.out.println("Parameters: " + parameters.toString()); } ExceptionAdapter ea = new ExceptionAdapter(e); ea.setSQLInfo(e, sql, parameters); throw ea; } }
Thanks!