복붙노트

[SPRING] Spring @ 트랜잭션 주석이 무시되었습니다.

SPRING

Spring @ 트랜잭션 주석이 무시되었습니다.

내 @ 거래 별 주석이 무시 된 것 같습니다. Spring 컨테이너 초기화시 오류가 없다. 내 방법은 봄 TX 프레임 워크에 의해 프록시되지 않은 것 같습니다. 내 서비스 메서드 실행 중에 JDBCTemplate에 의해 예상되는 RuntimeException이 발생합니다. 문제는 JDBC 연결이 롤백되지 않고 변경 사항이 지속된다는 것입니다. stacktrace는 내 서비스 메소드를 랩핑해야하는 프록시의 표시를 표시하지 않습니다.

편집 : 컨트롤러의 코드가 추가되었습니다.

편집 2 : 서비스 인터페이스 추가

다음은 내 서비스 인터페이스입니다.

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

여기 내 서비스가 있습니다.

@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 트랜잭션 설정이다.

<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>

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)

해결법

  1. ==============================

    1.제 생각에 당신은 dispatcher 서블릿에 속한 컨텍스트에 서비스 빈을 두었습니다. 컨트롤러 빈만이 살아야한다고 가정하고 루트 컨텍스트에서 트랜잭션 빈을 선언했습니다. 어노테이션 기반 트랜잭션 자동 프록시는 단일 컨텍스트 내에서만 적용되므로 다른 (잘못된) 컨텍스트의 서비스 bean은 영향을받지 않습니다. "DispatcherServlet이 다른 응용 프로그램 컨텍스트를 만드는 이유"에 대한 내 대답을 참조하십시오. 문제에 대한 자세한 설명은 근본적인 문제는 Spring MVC 애플리케이션에서 컨텍스트가 어떻게 구성되는지를 이해하지 못한다는 것이다.

    제 생각에 당신은 dispatcher 서블릿에 속한 컨텍스트에 서비스 빈을 두었습니다. 컨트롤러 빈만이 살아야한다고 가정하고 루트 컨텍스트에서 트랜잭션 빈을 선언했습니다. 어노테이션 기반 트랜잭션 자동 프록시는 단일 컨텍스트 내에서만 적용되므로 다른 (잘못된) 컨텍스트의 서비스 bean은 영향을받지 않습니다. "DispatcherServlet이 다른 응용 프로그램 컨텍스트를 만드는 이유"에 대한 내 대답을 참조하십시오. 문제에 대한 자세한 설명은 근본적인 문제는 Spring MVC 애플리케이션에서 컨텍스트가 어떻게 구성되는지를 이해하지 못한다는 것이다.

  2. ==============================

    2.@Transactional 어노테이션이 작동하려면 인터페이스를 정의해야합니다.

    @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를 구성 할 수 있습니다.

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

    편집하다

    SQLException로부터의 메세지는 다음과 같습니다.

    Field 'status' doesn't have a default value
    

    어쩌면 값을 제공해야하는 곳에서 null을 전달할 수도 있습니다. 또는이 게시물과 함께이 오류와 관련된 이상한 점을 확인하십시오.

  3. ==============================

    3.3 일간의 디버깅 후 마침내 주석이 무시 된 이유를 알게되었습니다.

    3 일간의 디버깅 후 마침내 주석이 무시 된 이유를 알게되었습니다.

    하위 컨텍스트 파일에있는 명령은 상위 스프링 컨텍스트에 의해 생성 된 빈에 액세스 할 수 없습니다.

    요청 디스패처에서 사용하는 myapp-servlet.xml로 이동해야했습니다.

    이제 제대로 작동하고 있습니다.

  4. from https://stackoverflow.com/questions/10538345/spring-transactional-annotations-ignored by cc-by-sa and MIT license