2012-05-10 20 views
6

Parece que se ignoran mis anotaciones @Transactionnal. No tengo errores en la inicialización del contenedor de Spring. Parece que mi método no ha sido procesado por el framework Spring TX. Durante la ejecución del método de mi servicio, JDBCTemplate lanza una RuntimeException esperada. El problema es que la conexión JDBC no se repliega y los cambios persisten. El stacktrace no muestra ningún signo del proxy que se supone que debe ajustar el método de mi servicio.Anotaciones de Spring @Transactional ignoradas

Editar: Se ha añadido el código del controlador

Editar 2: Se ha añadido la interfaz del servicio

Aquí está mi interfaz de servicio.

public interface ApplicationsService { 
    public Application getApplicationById(int id); 

    public void createApplication(Application application); 

    public void createInstance(Application application); 

    public Map<Integer, Application> getUserApplications(String username); 

    public Application newApplication(String email); 
} 

Aquí está mi servicio.

@Service 
public class ApplicationsServiceImpl implements ApplicationsService { 
    ... 
    @Transactional 
    public void createApplication(Application application){ 
     // Persisting the application. 
     applicationDAO.createApplication(application); 
     application.setId(
      applicationDAO.findApplicationId(application.getName(), application.getAccount().getEmail()) 
     ); 

     // Creating the physical instance. 
     createInstance(application); 
    } 
    ... 
} 

Resorte Controlador responsable de la llamada al método.

@Controller 
@RequestMapping("/applications") 
public class ApplicationsController { 
    ... 
    @Autowired 
    private ApplicationsService applicationsService; 
    ... 

    @RequestMapping(method=RequestMethod.POST) 
    public String saveApplication(
     @Valid Application application, 
     BindingResult bindingResult, 
     Principal principal 
    ){ 
     application.setAccount(this.accountService.getAccount(principal.getName())); 
     this.applicationsService.createApplication(application); 

     return "application/creatingApplication"; 
    } 
    ... 
} 

Aquí está mi configuración de la transacción primavera

<beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=" http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 

          http://www.springframework.org/schema/tx 
          http://www.springframework.org/schema/tx/spring-tx-3.1.xsd" 
> 
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="DADataSource"/> 
    </bean> 

    <tx:annotation-driven /> 
</beans> 

Durante la ejecución de la createApplication, un RuntimeException es lanzado por el JdbcTemplate y la transacción no se rollback.

GRAVE: Servlet.service() for servlet [DACloudWeb] in context with path [/DACloudWeb] threw exception [Request processing failed; 
nested exception is org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO instances ( serverId, appId, lastDeployment) VALUES ( ?,?,?) ]; SQL state [HY000]; error code [1364]; Field 'status' doesn't have a default value; nested exception is java.sql.SQLException: Field 'status' doesn't have a default value] with root cause 
    java.sql.SQLException: Field 'status' doesn't have a default value 
     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073) 
     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3609) 
     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3541) 
     at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002) 
     at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163) 
     at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2624) 
     at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2127) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2427) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2345) 
     at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2330) 
     at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
     at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
     at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:818) 
     at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:1) 
     at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:587) 
     at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:812) 
     at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:868) 
     at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:876) 
     at com.cspinformatique.dacloudWeb.applications.dao.InstanceJDBCDAO.createInstance(InstanceJDBCDAO.java:50) 
     at com.cspinformatique.dacloudWeb.applications.service.InstanceService.createInstance(InstanceService.java:42) 
     at com.cspinformatique.dacloudWeb.applications.service.ApplicationsService.createInstance(ApplicationsService.java:63) 
     at com.cspinformatique.dacloudWeb.applications.service.ApplicationsService.createApplication(ApplicationsService.java:52) 
     at com.cspinformatique.dacloudWeb.applications.controller.ApplicationsController.saveApplication(ApplicationsController.java:64) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213) 
     at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126) 
     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96) 
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617) 
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578) 
     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) 
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923) 
     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) 
     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) 
     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311) 
     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116) 
     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:182) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173) 
     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 
     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224) 
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) 
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) 
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) 
     at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) 
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
     at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987) 
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) 
     at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
     at java.lang.Thread.run(Thread.java:680) 
+1

¿Su método 'createApplication()' está siendo invocado por un método diferente en la misma clase? ¿O está siendo invocado desde afuera, por otra clase que recibe 'ApplicationService' inyectado? –

+0

No importa, acabo de ver en su rastro de pila que está siendo invocado externamente. –

+0

¿Su objeto de entidad 'Application' tiene un campo llamado' status'. Verifique las restricciones para eso en el nivel de la base de datos. ¿Requiere algún valor predeterminado? ¿Qué base de datos estás usando? Sería bueno si publicas tu código de entidad también. – raddykrish

Respuesta

9

Supongo que ha puesto los beans de servicio en el contexto que pertenece al servlet del asignador, donde se supone que solo los beans del controlador deben vivir, y luego ha declarado los beans de transacción en el contexto raíz. El auto-proxying de transacción basado en anotaciones solo se aplica dentro de un contexto único, por lo que los beans de servicio en el otro contexto (incorrecto) no se verán afectados. Consulte my answer to "Why DispatcherServlet creates another application context?" para obtener una descripción más completa del problema. El problema principal es que no entiende cómo se organizan los contextos en una aplicación Spring MVC.

+4

Tal vez pueda señalar un buen texto que explica cómo se organizan los contextos. Gracias :) –

5

es necesario definir una interfaz para los @Transactional anotaciones a trabajar:

public interface ApplicationsService { 
    public void createApplication(Application application); 
} 

Y la clase concreta:

@Service 
public class ApplicationsServiceImpl { 
    @Transactional 
    public void createApplication(Application application) { 
     // ... 
    } 
} 

alternativa, por el comentario de Kevin Welker, si no lo hacen desea una interfaz (aunque probablemente deba escribir una interfaz), puede configurar el uso proxy-target-class:

<tx:annotation-driven proxy-target-class="true" /> 

edición

El mensaje de su SQLException es:

Field 'status' doesn't have a default value 

Así que tal vez estás pasando en null donde usted debe proporcionar un valor? Alternativamente, marque this post para ver algunas rarezas asociadas con este error.

+4

No tiene que ser una interfaz, si configura para proxying de clase. Ver [esta respuesta para más] (http://stackoverflow.com/a/4143586/433348) –

+0

Intenté usar una interfaz y todavía tengo los mismos resultados. Actualizaré los cambios que hice. –

+0

Si junto con los repositorios, no necesita la interfaz y no necesita configurar nada, sino solo los métodos que se invocan desde las transacciones de ganancia del repositorio. – h22

2

Después de tres días de depuración, finalmente encontré la razón por la que se ignoraron mis anotaciones.

La instrucción <tx:annotation-driven/> ubicada en un archivo de contexto secundario no tiene acceso a los beans creados por su contexto principal de Spring.

Tuve que moverlo al myapp-servlet.xml utilizado por mi despachador de solicitudes.

Ahora, funciona correctamente.

+0

Esta no es la solución correcta. En el mejor de los casos, es una solución, y ha entendido mal qué contexto es el padre y cuál es el niño. Ver [mi respuesta] (http://stackoverflow.com/a/10564908/839646) para la explicación/solución correcta. –

Cuestiones relacionadas