복붙노트

[SPRING] Spring Jdbc 선언적 트랜잭션은 생성되었지만 아무것도 수행하지 않는다.

SPRING

Spring Jdbc 선언적 트랜잭션은 생성되었지만 아무것도 수행하지 않는다.

내 Spring 기반 웹 애플리케이션 내에서 선언적 트랜잭션 관리를 구성하려고 시도했으며 나와 협력하기를 거부했습니다.

두 가지 주요 문제가 있습니다.

첫 번째 문제는 모든 개별 쿼리가 데이터베이스에서 롤백되기 때문에 오히려 혼란 스럽습니다. 여기에는 SELECT 문도 포함됩니다. 어떤 쿼리가 데이터베이스에서 롤백 될 수 있습니까?

두 번째 문제는 트랜잭션 관리에 대한 내 구성이 아래에 요약되어 있습니다.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
       default-autowire="byName">

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*" rollback-for="Exception" />
  </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
 of an operation defined by a service in the service package -->
<aop:config>
  <aop:pointcut id="serviceOperations" expression="execution(* foo.bar.service.*.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations"/>
</aop:config>

<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="defaultAutoCommit" value="false" />
</bean>

<bean id="fooService" class="foo.bar.service.FooService" />

<bean id="barService" class="foo.bar.service.BarService" />

<bean id="zapService" class="foo.bar.service.ZapService" />

</beans>

이 문제를 해결하기 위해 방문한 모든 자습서 및 포럼에서 제 구성이 정확해야한다고 생각합니다. 그러나 나는 aop 및 스프링 거래를 완전히 이해하지 못하므로 중요한 것을 놓친 것일 수 있습니다.

위에서 언급했듯이 내 로그를 추적 할 수 있으며 트랜잭션 클래스뿐만 아니라 프록시도 내 서비스 클래스에 대해 생성 할 수 있습니다. 그러나 실제로 응용 프로그램을 실행하고 로그를 통해 추적 할 때 DataSourceTransactionManager 또는 트랜잭션을 작성, 커밋, 롤백 등의 작업을 처리하는 문장이 표시되지 않습니다.

실제로 아무 것도 실행되지 않고있는 것처럼 보일 것입니다. 그리고 나는 많은 다른 튜토리얼을 따라 많은 다른 방법을 시도했지만 정말 혼란 스럽습니다. 그러나 항상이 상황으로 끝납니다.

또한 Log4j 속성이 DataSourceTransactionManager에서 메시지를 올바르게 수신하도록 설정되어 있다는 것을 확신하지만, 아래에 해당 항목을 제공하여 내 부분에서 로깅 오류가 아닌지 확인합니다.

내 log4j는 다음 로거로 설정되어 트랜잭션을 추적합니다.

log4j.logger.org.springframework=INFO, file
log4j.logger.org.springframework.jdbc.datasource=DEBUG, file
log4j.logger.org.springframework.transaction=DEBUG, file

참고 : DEBUG에서 한 번에 최상위 로거를 실행했는데 이것이 바로 서비스 프록시가 생성되었음을 확인한 곳입니다.

아무도 무슨 일이 일어나고 있는지에 대한 통찰력을 가지고 있습니까? 나는 오히려 그 순간에 막혔다. 나는 트랜잭션이 생성되는 것과 관련된 부분을 보았으나 사용 된 트랜잭션의 흔적은 전혀 보지 못했다.

편집하다:

JB Nizet이 요청한 추가 정보.

내 전체 응용 프로그램은 주석 기반이므로 서비스 빈에는 @Service 주석이 달리고 이름 기반 자동 와이어 링을 통해 내 컨트롤러에 주입됩니다.

아래는 내 서비스 클래스 중 하나의 예입니다 (이름은 변경되었지만 applicationContext.xml을 반영합니다).

@Service("zapService")
public class ZapService
{

    /**
     * Data access object which performs the database look up
     */
    private ZapDAO zapDAO;

    /**
     * Add the given zap to the database
     *
     * @param zap a populated zap
     */
    public void processNewZap(Zap zap)
    {
        zapDAO.processNewZap(zap);
    }
}

보시다시피, 내 서비스 클래스는 컨트롤러 클래스와 DAO 클래스 사이의 단순한 프록시입니다. DAO는 실제로 데이터베이스 연결을 처리하는 곳입니다.

나는 거래를 처리 할 때 선호하는 관행 인 서비스를 거래로 만드는 것이 아니라, DAO 클래스를 만드는 것이 어딘가에 있다고 생각한다. 내가 틀렸다면 나를 바로 잡으십시오.

ZapDAO 클래스는 아래에 요약되어 있습니다.

@Repository("zapDAO")
public class ZapDAO
{

    /**
     * Log4j logger for this class
     */
    Logger logger = Logger.getLogger(ZapDAO.class);

    /**
     * Spring jdbc object to handle interacting with the database
     */
    private JdbcTemplate jdbcTemplate;

    public void processNewZap(Zap zap) {

        ... query constructing logic ...

        this.jdbcTemplate.update(INSERT_ZAP_QUERY_SQL);

    }

    public void setDataSource(DataSource dataSource)
    {
        Assert.notNull(dataSource, "You must supply a valid data source");

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}

jdbcTemplate을 사용하여 연결 및 쿼리를 처리합니다.

해결법

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

    1.그래서 수 시간의 검색, 디버깅, 리핑으로 시간이 지나자 마침내 모든 답변을 제공 한 작은 보석을 발견하게되었습니다.

    그래서 수 시간의 검색, 디버깅, 리핑으로 시간이 지나자 마침내 모든 답변을 제공 한 작은 보석을 발견하게되었습니다.

    나는 그런 문제를 의심하지 않았지만 위의 링크에 요약 된 단계를 따르면 완벽하게 작동했습니다.

    내 dispatch-servlet.xml 내에서 원래 구성 요소 스캔을 다음과 같이 선언했습니다.

    <context:component-scan base-package="foo.bar"/>
    

    모든 응용 프로그램 bean에 대한 부모 패키지입니다. 그래서 위의 링크에서 설명한 것처럼 Spring은 applicationContext.xml의 트랜잭션 서비스 빈을 트랜잭션에 대해 알지 못하는 dispatcher-servlet.xml의 서비스 빈으로 덮어 썼다.

    내가 한 모든 것은 위의 구성 요소 스캔을 분해하여 비 트랜잭션 빈을 포함하는 폴더 만 스캔합니다.

    <context:component-scan base-package="foo.bar.controller"/>
    <context:component-scan base-package="foo.bar.model"/>
    <context:component-scan base-package="foo.bar.service.display"/>
    <context:component-scan base-package="foo.bar.service.security"/>
    
    <!-- foo.bar.service gets scanned in applicationContext.xml and includes 
    transactions so we must make sure to not include it here. The transactional beans
    will be overridden in that case -->
    

    이 후 내 트랜잭션이 예상대로 정확하게 작동하고 트랜잭션 로그와 DataSourceTransactionManager가 로그 파일에 표시됩니다. 이것은 또한 데이터베이스에서 자동 롤백의 첫 번째 초기 문제점을 수정했습니다. 나는 그것이 거래의 부족과 밀접하게 연관되어 있었음에 틀림 없다.

  2. from https://stackoverflow.com/questions/5491748/spring-jdbc-declarative-transactions-created-but-not-doing-anything by cc-by-sa and MIT license