Spring @Transactional注释被忽略了

我的@Transactionnal注释似乎被忽略了。 我对Spring容器的初始化没有任何错误。 看起来我的方法还没有被Spring TX框架代理。 在执行我的服务方法期间,JDBCTemplate抛出了预期的RuntimeException。 问题是JDBC连接没有回滚并且更改是持久的。 堆栈跟踪不显示应该包装我的服务方法的任何代理符号。

编辑:添加了控制器的代码

编辑2:添加了服务的界面

这是我的服务界面。

public interface ApplicationsService { public Application getApplicationById(int id); public void createApplication(Application application); public void createInstance(Application application); public Map getUserApplications(String username); public Application newApplication(String email); } 

这是我的服务。

 @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); } ... } 

Spring Controller负责方法调用。

 @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"; } ... } 

这是我的Spring事务配置

       

在执行createApplication期间,JDBCTemplate将启动RuntimeException,并且不会回滚事务。

 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) 

我的猜测是你将服务bean放在属于调度程序servlet的上下文中,其中只有控制器bean应该存在,然后你在根上下文中声明了你的事务bean。 基于注释的事务自动代理仅适用于单个上下文,因此其他(错误)上下文中的服务bean不会受到影响。 请参阅我的回答“为什么DispatcherServlet创建另一个应用程序上下文?” 为了更全面地描述问题。 根本问题是您不了解Spring MVC应用程序中上下文的组织方式。

您需要为@Transactional注释定义一个接口才能工作:

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

具体课程:

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

或者,根据Kevin Welker的评论,如果不想要接口(尽管您可能应该编写接口),则可以配置use proxy-target-class

  

编辑

来自SQLException的消息是:

 Field 'status' doesn't have a default value 

那么也许你传递null应该提供一个值? 或者,请查看此post,了解与此错误相关的一些奇怪之处。

经过三天的调试,我终于找到了我的注释被忽略的原因。

位于子上下文文件中的指令无权访问其父Spring上下文创建的bean。

我不得不将它移动到我的请求调度程序使用的myapp-servlet.xml

现在,它正常运作。