2010-12-20 25 views
11

Estoy refactorizando el código de otros. Lo único que noto es la forma en que el sistema obtiene una conexión del grupo de conexiones.Obtener conexión a la base de datos desde un grupo de conexiones

La muestra es así. En cada llamada del método de servicio, el sistema realiza una búsqueda de contexto en el JNDI para la fuente de datos.

public class CheckinServlet extends HttpServlet { 

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 

     try { 
      //Obtain Connection 
      InitialContext initialContext = new InitialContext(); 
      javax.sql.DataSource ds = (javax.sql.DataSource) initialContext 
        .lookup("jdbc/mysqldb"); 
      java.sql.Connection conn = ds.getConnection(); 
      //business logic 
      //redirect 
     } finally { 
      conn.close(); 
     } 
    } 
} 

yo creo que hay un impacto en el rendimiento en hacer esto cada vez. Estoy pensando en otra forma de evitar la recuperación de una conexión desde un grupo de conexiones.

Estoy pensando en utilizar el método init() del servlet, pero creo que no es óptimo.

Respuesta

15

Hazlo una vez en un ServletContextListener en lugar de cada vez en init() de muchos servlets. El método contextInitialized() se ejecuta solo una vez durante el inicio de la aplicación.

public class Config implements ServletContextListener { 
    private static final String ATTRIBUTE_NAME = "config"; 
    private DataSource dataSource; 

    @Override 
    public void contextInitialized(ServletContextEvent event) { 
     ServletContext servletContext = event.getServletContext(); 
     String databaseName = servletContext.getInitParameter("database.name"); 
     try { 
      dataSource = (DataSource) new InitialContext().lookup(databaseName); 
     } catch (NamingException e) { 
      throw new RuntimeException("Config failed: datasource not found", e); 
     } 
     servletContext.setAttribute(ATTRIBUTE_NAME, this); 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent event) { 
     // NOOP. 
    } 

    public DataSource getDataSource() { 
     return dataSource; 
    } 

    public static Config getInstance(ServletContext servletContext) { 
     return (Config) servletContext.getAttribute(ATTRIBUTE_NAME); 
    } 
} 

configurarlo como sigue en web.xml:

<context-param> 
    <param-name>database.name</param-name> 
    <param-value>jdbc/mysqldb</param-value> 
</context-param> 
<listener> 
    <listener-class>com.example.Config</listener-class> 
</listener> 

lo puede obtener en el servlet de la siguiente manera (init() o doXXX() método, a elegir):

DataSource dataSource = Config.getInstance(getServletContext()).getDataSource(); 

que había sin embargo, refactorizarlo un paso más, el código JDBC debe colocarse preferiblemente en sus propias clases, no en servlets. Busque el patrón DAO.

+1

Hola señor, gracias por la respuesta siempre detallada. Pero una cosa me hace pensar sobre esto. ¿Por qué coloca el objeto Datasource como parámetros de contexto amplio? ¿No podemos simplemente hacer que el método getDataSource() sea estático? Realmente me gusta esta respuesta, pero quería aprender más sobre la razón de hacer esto. Gracias.. –

+0

Véalo también buen diseño. Un 'DataSource' es específico de una sola instancia' Config', no de múltiples instancias 'Config'. Aunque hay en este caso particular solo uno. – BalusC

+0

¿Se cierra la conexión de la base de datos cuando se llama contextDestroyed (ServletContextEvent)? –

3

El método que he utilizado en el pasado es la creación de una clase Singleton que contiene el origen de datos

P. ej

public class DatabaseConnectionManager { 

    DataSource ds; 

    public void init() { 
     InitialContext initialContext = new InitialContext(); 
     ds = (javax.sql.DataSource)initialContext.lookup("jdbc/mysqldb"); 
    } 

    public Connection getConnection() { 
     if(ds == null) init(); 

     return ds.getConnection(); 
    } 
} 

Esto significa que tiene una referencia compartida a su fuente de datos, quitando la sobrecarga de búsqueda jndi.

2

Agregando a lo que se ha dicho, hay un patrón de diseño llamado Service Locator, que es básicamente un singleton que contiene un registro llamado "servicio" que contiene sus objetos JNDI.

Básicamente, si el objeto no se encuentra en el registro, el servicio se toma del grupo JNDI y se registra en el registro. La siguiente llamada simplemente extraerá el objeto del registro.

Espero que esto ayude.

3

Acabo de hacer algunas pruebas con esto, y encontré que el tiempo de búsqueda de jndi no es tan pesado. 50,000 búsquedas en aproximadamente 1 segundo aquí.

Por lo tanto, en muchos casos, no veo una razón para almacenar en caché el DataSource en absoluto.

El problema con el almacenamiento en caché es que puede terminar con un DataSource obsoleto, lo que le obliga a reiniciar su aplicación si cambia algo relacionado con la definición del origen de datos.

Cuestiones relacionadas