2011-09-29 14 views
22

Estoy tratando de determinar si realmente estoy usando la agrupación de conexiones JDBC. Después de investigar, la implementación parece demasiado fácil. Más fácil que una conexión normal, de hecho, me gustaría verificarlo.¿Estoy utilizando la agrupación de conexiones JDBC?

Aquí es mi clase de conexión:

public class DatabaseConnection { 

Connection conn = null; 

public Connection getConnection() { 

    BasicDataSource bds = new BasicDataSource(); 
    bds.setDriverClassName("com.mysql.jdbc.Driver"); 
    bds.setUrl("jdbc:mysql://localhost:3306/data"); 
    bds.setUsername("USERNAME"); 
    bds.setPassword("PASSWORD"); 

    try{ 
     System.out.println("Attempting Database Connection"); 
     conn = bds.getConnection(); 
     System.out.println("Connected Successfully"); 
    }catch(SQLException e){ 
     System.out.println("Caught SQL Exception: " + e); 
    } 
    return conn; 
} 

public void closeConnection() throws SQLException { 
    conn.close(); 
} 

}

Es esto cierto agrupación de conexiones? Estoy utilizando la conexión en otra clase como tal:

 //Check data against database. 
    DatabaseConnection dbConn = new DatabaseConnection(); 
    Connection conn; 
    ResultSet rs; 
    PreparedStatement prepStmt; 

    //Query database and check username/pass against table. 
    try{ 
     conn = dbConn.getConnection(); 
     String sql = "SELECT * FROM users WHERE username=? AND password=?"; 
     prepStmt = conn.prepareStatement(sql); 
     prepStmt.setString(1, user.getUsername()); 
     prepStmt.setString(2, user.getPassword()); 
     rs = prepStmt.executeQuery(); 

     if(rs.next()){ //Found Match. 
      do{ 
       out.println("UserName = " + rs.getObject("username") + " Password = " + rs.getObject("password")); 
       out.println("<br>"); 
      } while(rs.next()); 
     } else { 
      out.println("Sorry, you are not in my database."); //No Match. 
     } 

     dbConn.closeConnection(); //Close db connection. 

    }catch(SQLException e){ 
     System.out.println("Caught SQL Exception: " + e); 
    } 

Respuesta

45

Suponiendo que es el BasicDataSource es de DBCP, entonces sí, está utilizando un pool de conexiones. Sin embargo, está recreando otro grupo de conexiones en cada adquisición de conexión. No estás realmente agrupando conexiones del mismo grupo. Necesita crear el grupo de conexiones solo una vez en el inicio de la aplicación y obtener cada conexión desde él. Tampoco debería mantener la conexión como una variable de instancia. También debe cerrar la conexión, la declaración y el conjunto de resultados para asegurarse de que los recursos estén debidamente cerrados, también en caso de excepciones. El try-with-resources statement de Java 7 es útil en esto, cerrará automáticamente los recursos cuando finalice el bloque try.

Aquí es una reescritura de menor importancia:

public final class Database { 

    private static final BasicDataSource dataSource = new BasicDataSource(); 

    static { 
     dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
     dataSource.setUrl("jdbc:mysql://localhost:3306/data"); 
     dataSource.setUsername("USERNAME"); 
     dataSource.setPassword("PASSWORD"); 
    } 

    private Database() { 
     // 
    } 

    public static Connection getConnection() throws SQLException { 
     return dataSource.getConnection(); 
    } 

} 

(esto puede si es necesario refactorizar como una fábrica de resumen para mejorar enchufabilidad)

y

private static final String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?"; 

public boolean exist(User user) throws SQLException { 
    boolean exist = false; 

    try (
     Connection connection = Database.getConnection(); 
     PreparedStatement statement = connection.prepareStatement(SQL_EXIST); 
    ) { 
     statement.setString(1, user.getUsername()); 
     statement.setString(2, user.getPassword()); 

     try (ResultSet resultSet = preparedStatement.executeQuery()) { 
      exist = resultSet.next(); 
     } 
    }  

    return exist; 
} 

la que se va a utilizar de la siguiente manera:

try { 
    if (!userDAO.exist(username, password)) { 
     request.setAttribute("message", "Unknown login. Try again."); 
     request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); 
    } else { 
     request.getSession().setAttribute("user", username); 
     response.sendRedirect("userhome"); 
    } 
} catch (SQLException e) { 
    throw new ServletException("DB error", e); 
} 

En un entorno Java EE real, sin embargo, debe delegar la creación del DataSource en el servidor de contenedor/aplicación y obtenerlo de JNDI. En el caso de Tomcat, consulte también, por ejemplo, este documento: http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html

+0

Wow, gracias por la reescritura también. Ayuda perfecta para alguien nuevo como yo. – ryandlf

+0

¿Esta solución será segura? ¿Debo llamar a connection.close(); – swapyonubuntu

+0

@swapyonubuntu: close se hace automáticamente con la nueva declaración de Java7 'try-with-resources' https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – BalusC

3

Parece que no se ha agrupado. Debe almacenar el DataSource en DatabaseConnection en lugar de crear uno nuevo con cada llamada getConnection(). getConnection() debería devolver datasource.getConnection().

2

Parece un uso de DBCP. Si es así, entonces sí. Ya está agrupado. Y aquí está el valor predeterminado de la propiedad del grupo de DBCP.

/** 
* The default cap on the number of "sleeping" instances in the pool. 
* @see #getMaxIdle 
* @see #setMaxIdle 
*/ 
public static final int DEFAULT_MAX_IDLE = 8; 
/** 
* The default minimum number of "sleeping" instances in the pool 
* before before the evictor thread (if active) spawns new objects. 
* @see #getMinIdle 
* @see #setMinIdle 
*/ 
public static final int DEFAULT_MIN_IDLE = 0; 
/** 
* The default cap on the total number of active instances from the pool. 
* @see #getMaxActive 
*/ 
public static final int DEFAULT_MAX_ACTIVE = 8; 
1

Como seguimiento a la solución de BalusC, a continuación es una aplicación que puede utilizarse dentro de una aplicación que requiere más de una conexión, o en una biblioteca común que no sabrían las propiedades de conexión de antemano ..

import org.apache.commons.dbcp.BasicDataSource; 

import java.sql.Connection; 
import java.sql.SQLException; 
import java.util.concurrent.ConcurrentHashMap; 

public final class Database { 

    private static final ConcurrentHashMap<String, BasicDataSource> dataSources = new ConcurrentHashMap(); 

    private Database() { 
     // 
    } 

    public static Connection getConnection(String connectionString, String username, String password) throws SQLException { 

     BasicDataSource dataSource; 

     if (dataSources.containsKey(connectionString)) { 
      dataSource = dataSources.get(connectionString); 
     } else { 
      dataSource = new BasicDataSource(); 
      dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
      dataSource.setUrl(connectionString); 
      dataSource.setUsername(username); 
      dataSource.setPassword(password); 
      dataSources.put(connectionString, dataSource); 
     } 

     return dataSource.getConnection(); 

    } 

} 
+0

Esta solución no funciona siempre. Está sujeto a condiciones de carrera a pesar de utilizar ConcurrentHashMap. –

Cuestiones relacionadas