2010-08-19 25 views
7

Estoy usando Spring MVC para construir una capa delgada sobre una base de datos de SQL Server. Cuando comencé a probar, parece que no maneja el estrés muy bien :). Estoy usando Apache Commons DBCP para manejar la agrupación de conexiones y la fuente de datos.¿Cuál es la forma correcta de manejar las conexiones JDBC con Spring y DBCP?

Cuando intenté por primera vez ~ 10-15 conexiones simultáneas, solía colgar y tenía que reiniciar el servidor (para el desarrollador estoy usando Tomcat, pero voy a tener que implementarlo en Weblogic).

Estos son mis definiciones de frijol de primavera:

<bean id="dataSource" destroy-method="close" 
     class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> 
    <property name="url" value="[...]"/> 
    <property name="username" value="[...]" /> 
    <property name="password" value="[...]" /> 
</bean> 

<bean id="partnerDAO" class="com.hp.gpl.JdbcPartnerDAO"> 
    <constructor-arg ref="dataSource"/> 
</bean> 

<!-- + other beans --> 

y así es como yo los utilizo:

// in the DAO 
public JdbcPartnerDAO(DataSource dataSource) { 
    jdbcTemplate = new JdbcTemplate(dataSource); 
} 

// in the controller 
@Autowired 
private PartnerDAO partnerDAO; 

// in the controller method 
Collection<Partner> partners = partnerDAO.getPartners(...); 

Después de leer todo un poco, me encontré con los maxWait, maxActive y maxIdle propiedades el BasicDataSource (desde GenericObjectPool). Aquí viene el problema. No estoy seguro de cómo debería configurarlos, en cuanto a rendimiento. Por lo que sé, Spring debería administrar mis conexiones, así que no debería preocuparme por liberarlas.

<bean id="dataSource" destroy-method="close" 
     class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> 
    <property name="url" value="[...]"/> 
    <property name="username" value="[...]" /> 
    <property name="password" value="[...]" /> 
    <property name="maxWait" value="30" /> 
    <property name="maxIdle" value="-1" /> 
    <property name="maxActive" value="-1" /> 
</bean> 

En primer lugar, me puse maxWait, por lo que no sería colgar y en lugar de lanzar una excepción cuando no hay conexión estaba disponible de la piscina. El mensaje de excepción fue:

No se pudo obtener la conexión JDBC; la excepción jerarquizada es org.apache.commons.dbcp.SQLNestedException: No se puede obtener una conexión, error de tiempo de espera de la piscina a la espera de objetos abandonados

Hay algunas consultas de larga ejecución, pero la excepción fue lanzada independientemente de la complejidad de la consulta.

Luego, configuré maxActive y maxIdle para que no arrojara las excepciones en primer lugar. Los valores predeterminados son 8 para maxActive y maxIdle (no entiendo por qué); si los configuro en -1 no hay más excepciones lanzadas y todo parece para que funcione bien.

Teniendo en cuenta que esta aplicación debería admitir una gran cantidad de solicitudes simultáneas ¿está bien dejar esta configuración en infinito? ¿Spring realmente administrará mis conexiones, teniendo en cuenta los errores que estaba recibiendo? ¿Debería cambiar a C3P0 teniendo en cuenta que está algo muerto?

+0

Si recibe alguna excepción, publicar la stacktrace ayudará a identificar el problema fácilmente. ¿Hay alguna consulta de larga ejecución en la que vea los problemas? –

+0

He actualizado mi publicación con el mensaje de excepción y alguna información adicional. –

Respuesta

6

Como ya descubrió, el grupo de conexiones de dbcp predeterminado es de 8 conexiones, por lo que si desea ejecutar 9 consultas simultáneas, se bloqueará una de ellas.Le sugiero que se conecte a su base de datos y ejecute exec sp_who2, que le mostrará lo que está conectado y activo, y si las consultas están siendo bloqueadas. Luego puede confirmar si el problema está en la base de datos o en su código.

Siempre que utilice la familia de objetos JdbcTemplate de Spring, sus conexiones se administrarán como espera, y si desea utilizar un DataSource sin formato, asegúrese de utilizar DataSourceUtils para obtener una conexión.

Otra sugerencia - antes del muelle 3, no usar nunca JdbcTemplate, se adhieren a SimpleJdbcTemplate, todavía se puede acceder a los mismos métodos que utilizan SimpleJdbcTemplate.getJdbcOperations(), pero debe encontrarse escribir código mucho más agradable el uso de los genéricos, y eliminar la necesidad crear alguna vez instancias JdbcTemplate/NamedParameterJdbcTemplate.

2

Cambiemos la perspectiva.

sino la excepción fue lanzada independientemente de la complejidad consulta

Podría ser debido a que la mesa o los registros de la tabla, que se está consultando en contra ha sido bloqueada (por alguna otra transacción activa) y por lo tanto se agota el tiempo.

Intente ejecutar la misma consulta desde SQLServer Client y, si lleva mucho tiempo, puede estar seguro de que es la tabla o el bloqueo de registros lo que está causando esto.

+0

Veo su punto, pero el problema desaparece completamente cuando configuro los parámetros 'maxActive' y' maxIdle' de la fuente de datos a un valor grande (o infinito). Esto me lleva a pensar que el problema es de ConnectionPool, como dice el mensaje de excepción. –

8

El parámetro DBCP maxWait se debe definir en milisegundos. 30 ms tiene un valor muy bajo, considere aumentarlo a 30000 ms y vuelva a intentarlo.

Cuestiones relacionadas