복붙노트

[SPRING] @Transactional 메서드에서 Spring 내에서 트랜잭션이 시작되지 않습니다.

SPRING

@Transactional 메서드에서 Spring 내에서 트랜잭션이 시작되지 않습니다.

Spring (3.0.5), Hibernate (3.6.0) 및 Wicket (1.4.14)를 사용하여 응용 프로그램을 개발하는 동안 이상한 문제가 발생합니다. 문제는 : 내가 데이터베이스에 개체를 저장하거나 수정할 수 없다는 것입니다. EntityManager.persist (foo)에 대한 객체 또는 호출의 모든 변경 사항이 단순히 무시된다는 것을 의미하지 않습니다. 작업을 선택합니다.

예제 케이스는 간단합니다 - 일부 wicket 페이지에서 다음과 같이 데이터베이스에 객체를 저장하려고합니다.

public class ComicDetailsPage extends PublicBasePage {

@Override
protected void onConfigure() {
    System.out.println("In onConfigure");
    super.onConfigure();
    comicDAO.insert("abc");

}

@SpringBean(name="comicDAO")
private ComicDAO comicDAO;

    (....)

여기 코믹 DAO입니다

@Service
public class ComicDAO {

@PersistenceContext
private EntityManager em;

(...)

@Transactional
public void insert(String title) {
    Comic c = new Comic();
    c.setTitle(title);
    em.persist(c);
}

@Transactional
public Comic add1toTitle(int pk) {
    System.out.println("Beginning fetching");
    Comic c = em.find(Comic.class, pk);
    System.out.println("Fetched updating");
    c.setTitle(c.getTitle()+"1");
    System.out.println("Updated persisting");
    em.persist(c);
    System.out.println("Persisted returning");
    return c;
}

나는 로깅을 켜고 여기서 로그의 관련 부분 (Hibernate와 Spring 모두 TRACE로 설정된다)이다. 나는 ** 중요한 라인이라고 생각하는 라인에 **를 추가했다.

In onConfigure
01:53:19.330 [qtp2119047503-15] DEBUG o.s.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
**01:53:19.330 [qtp2119047503-15] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13006687993**
**01:53:19.330 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - begin**
01:53:19.330 [qtp2119047503-15] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
01:53:19.335 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - current autocommit status: true
01:53:19.335 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - disabling autocommit
01:53:19.336 [qtp2119047503-15] TRACE org.hibernate.jdbc.JDBCContext - after transaction begin
01:53:19.336 [qtp2119047503-15] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13006687993
01:53:19.336 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - setting flush mode to: AUTO
01:53:19.336 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - setting cache mode to: NORMAL
01:53:19.337 [qtp2119047503-15] TRACE org.hibernate.engine.IdentifierValue - id unsaved-value: 0
01:53:19.337 [qtp2119047503-15] TRACE org.hibernate.event.def.AbstractSaveEventListener - transient instance of: pl.m4ks.comics.entity.Comic
01:53:19.337 [qtp2119047503-15] TRACE org.hibernate.event.def.DefaultPersistEventListener - saving transient instance
**01:53:19.338 [qtp2119047503-15] TRACE org.hibernate.event.def.AbstractSaveEventListener - saving [pl.m4ks.comics.entity.Comic#<null>]**
**01:53:19.341 [qtp2119047503-15] DEBUG org.hibernate.event.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress**
01:53:19.341 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - closing session
01:53:19.341 [qtp2119047503-15] TRACE org.hibernate.jdbc.ConnectionManager - connection already null in cleanup : no action
01:53:19.341 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - commit
**01:53:19.341 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - automatically flushing session**
01:53:19.341 [qtp2119047503-15] TRACE org.hibernate.jdbc.JDBCContext - before transaction completion
01:53:19.341 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - before transaction completion
01:53:19.342 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
01:53:19.342 [qtp2119047503-15] DEBUG org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.jdbc.JDBCContext - after transaction completion
01:53:19.342 [qtp2119047503-15] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - after transaction completion
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - closing session
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.jdbc.ConnectionManager - performing cleanup
01:53:19.342 [qtp2119047503-15] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.jdbc.JDBCContext - after transaction completion
01:53:19.342 [qtp2119047503-15] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
01:53:19.342 [qtp2119047503-15] TRACE org.hibernate.impl.SessionImpl - after transaction completion

물론 어떤 객체도 데이터베이스에 저장되지 않습니다.

마지막 파일 - 내 applicationCOntext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans (...)>

    <context:component-scan base-package="pl.m4ks.comics"/>
    <context:annotation-config /> 

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:8889/comics" />
        <property name="username" value="root"/>
        <property name="password" value="root" />          
    </bean>

    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="main" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
         <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
        <property name="packagesToScan">
             <value>pl.m4ks.comics</value>
        </property>
    </bean>


    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <tx:annotation-driven transaction-manager="txManager"  proxy-target-class="true"/>
</beans>

나는 그 문제가 무엇이 될 수 있고 어떻게 해결할 수 있을지 전혀 모른다. 내 코드에서 트랜잭션을 관리하고 싶지 않습니다. 이것이 Spring의 목적입니다.

해결법

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

    1.a) 당신은 Hibernate SessionFactory와 JPA EntitymanagerFactory를 정의하고있다. 어느 쪽이 될 것인가? Hibernate의 Session API 또는 JPA의 Entitymanager API를 Hibernate와 함께 제공 업체로 사용하십시오. 둘 다 사용할 수는 없습니다.

    a) 당신은 Hibernate SessionFactory와 JPA EntitymanagerFactory를 정의하고있다. 어느 쪽이 될 것인가? Hibernate의 Session API 또는 JPA의 Entitymanager API를 Hibernate와 함께 제공 업체로 사용하십시오. 둘 다 사용할 수는 없습니다.

    b) HibernateTransactionManager를 정의했지만 코드에서 EntityManager를 사용하고 있으므로 JpaTransactionManager가 필요하다.

    <bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEmf"/>
    </bean
    

    다음은 applicationContext.xml의 주석 처리 된 버전입니다.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans (...)>
    
        <context:component-scan base-package="pl.m4ks.comics"/>
        <context:annotation-config /> 
    
        <bean id="dataSource" 
        class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:8889/comics" />
            <property name="username" value="root"/>
            <property name="password" value="root" />          
        </bean>
    
        <!-- use either this: -->
        <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="persistenceUnitName" value="main" />
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <!-- or this -->
        <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
             <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            <property name="packagesToScan">
                 <value>pl.m4ks.comics</value>
            </property>
        </bean>
        <!-- (but not both) --> 
    
        <!-- this is correct for AnnotationSessionFactoryBean, but not if you use
             LocalContainerEntityManagerFactoryBean --> 
        <bean id="txManager" 
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
    
        <!-- not necessary, <context:annotation-config /> automatically includes this -->
        <bean 
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
        <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
    </beans>
    

    그리고 디자인 노트 : DAO는 트랜잭션이 아니어야합니다. 트랜잭션을 관리하는 서비스 계층을 사용해야합니다. 참조를 위해이 질문 및 많은 다른 사람을보십시오.

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

    2.최대 절전 모드 설정에서 hibernate.connection.autocommit = true를 설정해 보셨습니까? 그러면 문제가 해결 될 것입니다. 그러나 접근 방법이 얼마나 효율적인지 알아 내야합니다.

    최대 절전 모드 설정에서 hibernate.connection.autocommit = true를 설정해 보셨습니까? 그러면 문제가 해결 될 것입니다. 그러나 접근 방법이 얼마나 효율적인지 알아 내야합니다.

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

    3.EntityManager에서 다음 메소드를 호출해야한다.

    EntityManager에서 다음 메소드를 호출해야한다.

    플러시()

    데이터베이스에 실제 저장하려면

  4. from https://stackoverflow.com/questions/5372859/no-transaction-starts-within-spring-transactional-method by cc-by-sa and MIT license