Spring-현재 스레드에 사용 가능한 실제 트랜잭션이있는 EntityManager가 없음- 'persist'호출을 안정적으로 처리 할 수 ​​없음


137

Spring MVC 웹 애플리케이션에서 엔티티 모델을 데이터베이스에 저장하기 위해 "persist"메소드를 호출하려고 할 때이 오류가 발생합니다. 인터넷 에서이 특정 오류와 관련된 게시물이나 페이지를 실제로 찾을 수 없습니다. 그것은 EntityManagerFactory bean에 문제가있는 것처럼 보이지만 Spring 프로그래밍에 익숙하지 않기 때문에 모든 것이 잘 초기화되어 있고 웹의 다양한 자습서 기사에 따라 보입니다.

dispatcher-servlet.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:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/jdbc
  http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
  http://www.springframework.org/schema/data/jpa
  http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
  http://www.springframework.org/schema/data/repository
  http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">

    <context:component-scan base-package="wymysl.Controllers" />
    <jpa:repositories base-package="wymysl.repositories"/> 
    <context:component-scan base-package="wymysl.beans" /> 
    <context:component-scan base-package="wymysl.Validators" /> 
    <bean
     class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

     <bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>

     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
        <property name="username" value="system" />
        <property name="password" value="polskabieda1" />
    </bean>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            <property name="showSql" value="true" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">10</prop>
        </props>
    </property>
</bean>

    <mvc:annotation-driven />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
</bean>

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


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/resources/*" location="/resources/css/"  
    cache-period="31556926"/>



</beans>

RegisterController.java

@Controller
public class RegisterController {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    PasswordValidator passwordValidator;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.setValidator(passwordValidator);
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String register(Person person) {


        return "register";

    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
        if(result.hasErrors()) {
            return "register";
        } else {
            entityManager.persist(person);
            return "index";

        }




    }

1
오류에서 알 수 있듯이 트랜잭션이 없습니다. 로 등록 방법에 주석을 답니다 @Transaction.
Rohit

답변:


260

나는 같은 문제가 있었고 그 방법에 주석을 달았고 @Transactional효과가있었습니다.

업데이트 : 기본적으로 PersistenceContext가 보이는 Spring 문서를 확인하는 것은 Transaction 유형이므로 메소드는 트랜잭션이어야합니다 ( http://docs.spring.io/spring/docs/current/spring-framework-reference/ html / orm.html ) :

@PersistenceContext 어노테이션에는 선택적 속성 유형이 있으며 기본값은 PersistenceContextType.TRANSACTION입니다. 이 기본값은 공유 EntityManager 프록시를 수신하는 데 필요한 것입니다. 대안 인 PersistenceContextType.EXTENDED는 완전히 다른 일입니다. 이로 인해 소위 확장 된 EntityManager가 생성되며 이는 스레드 안전이 아니므로 스프링 관리 싱글 톤 Bean과 같이 동시에 액세스되는 컴포넌트에서 사용해서는 안됩니다. 확장 된 EntityManager는 예를 들어 세션에 상주하는 상태 저장 구성 요소에서만 사용되어야합니다. EntityManager의 수명주기는 현재 트랜잭션에 연결되어 있지 않고 애플리케이션에 전적으로 달려 있습니다.


71
포함하지 않는 방법 경우 @Transactionalannotion가있는 메소드를 호출 @Transactional같은 클래스 파일에 주석을, 당신은 또한 (I 직면했다 무엇이)이 오류 강타됩니다.
Jacob van Lingen

5
서비스 클래스에 주석을 달았습니다 @Transactional. 그것이 올바른 방법인지 확실하지 않지만 잘 작동하는 것 같습니다 ...
milosmns

8
언급해야 할 또 다른 사항은이 주석은 달리 작동하지 않으므로 공용 메소드에 사용해야한다는 것입니다.
유리 크라 베

7
@Transactional은 공용 메소드에서만 작동합니다.
Andrei_N

7
참고로 이것은 javax.transaction.Transactional 주석 (Spring 주석이 아님)이 필요합니다.
java-addict301

85

스프링 데이터 저장소에서 deleteBy 사용자 정의 메소드를 사용하려고 시도하는 중에이 예외가 발생했습니다. JUnit 테스트 클래스에서 조작을 시도했습니다.

@TransactionalJUnit 클래스 레벨에서 주석을 사용할 때는 예외가 발생하지 않습니다 .


8
나는 같은 상황에 있었고, 테스트 클래스에 주석을 달지 않고 서비스 방법에 주석을 달았으므로 테스트가 아니더라도 속임수를 사용했습니다.
폴 넬슨 베이커

@Transactional클래스 수준에서 서비스의 다른 트랜잭션을 조작하는 가능한 테스트 문제를 숨길 수 있습니다.
Zon

1
@Trasactional실제로 데이터베이스와 상호 작용하고 제대로 작동하기 때문에 저장소 방법을 사용 했습니다.
Harish Kumar Saini

22

이 오류로 인해 3 일 동안 여우가 나타 났으며, 내가 직면 한 상황에서도 같은 오류가 발생했습니다. 내가 찾은 모든 조언에 따라 구성을 가지고 놀았지만 아무 소용이 없었습니다.

결국 나는 그것이 실행중인 서비스가 일반적인 jar에 포함되어 있다는 차이점을 발견했습니다. 문제는 AspectJ가 서비스 인스턴스화를 동일하게 취급하지 않는 것으로 나타났습니다. 사실상 프록시는 단순히 메소드 호출 전에 모든 일반적인 Spring 매직이 실행되지 않고 기본 메소드를 호출하는 것입니다.

결국 예제에 따라 서비스에 배치 된 @Scope 주석이 문제를 해결했습니다.

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
        CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
        criteriaDelete.from(clazz);
        return entityManager.createQuery(criteriaDelete).executeUpdate();
    }

}

내가 게시 한 방법은 삭제 방법이지만 주석은 동일한 방식으로 모든 지속성 방법에 영향을 미칩니다.

이 게시물이 항아리에서 서비스를로드 할 때 같은 문제로 어려움을 겪은 다른 사람에게 도움이되기를 바랍니다.


@Scope(proxyMode = ScopedProxyMode.INTERFACES)인터페이스를 구현하는 DAO 클래스에 추가 하는 것은 정말 중요합니다. 나는 하루 종일이 오류를 알아 내고 솔루션은 유일한 방법입니다. 대단히 감사합니다!
Thach Van

1
당신의 대답에서 하나의 L' annotation은 아마 약 3 일을 저를 구했습니다. 나는 막 부종의 실제 힘을 경험했습니다. Дякс.
Oleksii Kyslytsyn


8

boardRepo.deleteByBoardId (id);

같은 문제에 직면했다. GOT javax.persistence.TransactionRequiredException : 현재 스레드에 사용 가능한 실제 트랜잭션이있는 EntityManager가 없음

컨트롤러 / 서비스 위에 @Transactional 주석 을 추가하여 해결했습니다 .


7

저도 같은 문제를 겪고 난 추가 tx:annotation-drivenapplicationContext.xml그것은했다.


4

동일한 구성 요소 내에서 비 ​​트랜잭션 방식으로 이미 트랜잭션이 주석 처리 된 메소드에 액세스 할 때 동일한 오류가 발생했습니다.

Before:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          executeQuery(); //<-- Wrong
        }
    }

    //In another bean:
     marketObserver.startObserving();

자체 참조 구성 요소에서 executeQuery ()를 호출하여 오류를 수정했습니다.

Fixed version:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Autowired
        private GenericApplicationContext context;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          context.getBean(MarketObserver.class).executeQuery(); //<-- Works
        }
    }

3

org.springframework.transaction.annotation.Transactional테스트 클래스의 클래스 수준에서 주석을 추가하면 문제가 해결되었습니다.


3

thie 오류에 대한 답변을 검색 하는 다른 사용자를 위한 참고 사항입니다 . 또 다른 일반적인 문제는 다음과 같습니다.

일반적으로 @transactional동일한 클래스 내에서 메소드를 호출 할 수 없습니다 .

(AspectJ를 사용하는 방법과 수단이 있지만 리팩토링이 훨씬 쉬울 것입니다)

따라서 @transactional메소드 를 보유하는 호출 클래스 및 클래스가 필요 합니다.


2

우리에게는 문제가 여러 구성 파일의 동일한 컨텍스트 설정으로 내려졌습니다. 여러 구성 파일에서 다음을 복제하지 않았는지 확인하십시오.

<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />

2

@Transaction잘못된 메소드 / 액션 수준에서 사용할 때 동일한 오류 코드가있었습니다 .

methodWithANumberOfDatabaseActions() { 
   methodA( ...)
   methodA( ...)
}

@Transactional
void methodA( ...) {
  ... ERROR message
}

물론 @Transactional방법 바로 위에 배치해야했습니다 methodWithANumberOfDatabaseActions().

그것은 내 경우의 오류 메시지를 해결했습니다.


0

에서 모드를 제거했습니다

<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />

이 작품을 만들기 위해


0

나는 며칠 동안이 문제를 겪었고 온라인 어디에서나 도움이되는 것을 발견하지 못했습니다. 다른 사람을 도울 수 있도록 여기에 내 답변을 게시하고 있습니다.

필자의 경우 원격을 통해 호출되는 마이크로 서비스를 작업하고 있었고 서비스 수준의 @Transactional 주석이 원격 프록시에 의해 선택되지 않았습니다.

서비스와 dao 레이어 사이에 델리게이트 클래스를 추가하고 델리게이트 메소드를 트랜잭션으로 표시하면이 문제가 해결되었습니다.


0

이것은 우리에게 도움이되었을 것입니다. 미래에 다른 사람들을 도울 수도 있습니다. @Transaction우리를 위해 일하지 않았지만 이것은 다음과 같습니다.

@ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")


0

당신이 가지고 있다면

@Transactional // Spring Transactional
class MyDao extends Dao {
}

그리고 슈퍼 클래스

class Dao {
    public void save(Entity entity) { getEntityManager().merge(entity); }
}

그리고 당신은 전화

@Autowired MyDao myDao;
myDao.save(entity);

Spring TransactionInterceptor를 얻지 못할 것입니다 (거래를 제공합니다).

이것이 당신이해야 할 일입니다.

@Transactional 
class MyDao extends Dao {
    public void save(Entity entity) { super.save(entity); }
}

믿을 수 없지만 사실입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.