복붙노트

[SPRING] 스프링 부트 최대 절전 모드 트랜잭션 없음

SPRING

스프링 부트 최대 절전 모드 트랜잭션 없음

나는 봄 부팅을 사용하고 있으며 완벽하게 엔티티 관리자가되었습니다. 그리고 엔티티 관리자로부터 세션 팩토리를 테스트하고 예제로 사용하기로 결정했습니다. 하지만 다음 문제가 발생합니다 : javax.persistence.TransactionRequiredException : 트랜잭션이 진행되고 있지 않습니다.

속성들

spring.datasource.url= jdbc:postgresql://localhost:5432/ring
spring.datasource.username=postgres
spring.datasource.password=root

spring.jpa.show-sql = false
spring.jpa.properties.hibernate.format_sql=false

#Note: The last two properties on the code snippet above were added to suppress an annoying exception
# that occurs when JPA (Hibernate) tries to verify PostgreSQL CLOB feature.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false

spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext

서비스 클래스

package kz.training.springrest.service;

import kz.training.springrest.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

@Service
public class UserService {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void insertUser(User user) {
        SessionFactory sessionFactory = entityManager.unwrap(Session.class).getSessionFactory();
        Session session = sessionFactory.getCurrentSession();
        session.save(user);
    }

}

달리는 사람

package kz.training.springrest.run;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EntityScan("kz.training.springrest.entity")
@EnableTransactionManagement
@ComponentScan(basePackages="kz.training.springrest")
public class SpringrestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringrestApplication.class, args);
    }
}

어떻게 해결할 수있는 아이디어가 있습니까?

해결법

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

    1.서비스 방법이 불필요하게 복잡 해지는 이유를 잘 모르겠습니다. 당신은이 방법으로 간단하게 할 수 있어야합니다.

    서비스 방법이 불필요하게 복잡 해지는 이유를 잘 모르겠습니다. 당신은이 방법으로 간단하게 할 수 있어야합니다.

    @Transactional
    public void insertUser(User user) {
      entityManager.persist( user );
    }
    

    네이티브 Hibernate Session에 대한 액세스가 필요한 지점이 있으면 다음과 같이 세션을 간단히 풀고 사용할 수 있습니다.

    @Transactional
    public void doSomethingFancyWithASession() {
      Session session = entityManager.unwrap( Session.class );
      // use session as needed
    }
    

    여기서 Spring은 @PersistenceContext 어노테이션을 사용하여 Spring이 이미 기능하는 EntityManager 인스턴스를 제공한다는 것이다. 이 인스턴스는 스프링 bean이 실행되는 현재 스레드에 의해 안전하게 사용할 수 있습니다.

    둘째, @Transactional을 사용하면 Spring의 트랜잭션 관리가 EntityManager가 트랜잭션에 바인딩되었는지 여부를 자동으로 확인하게됩니다. RESOURCE_LOCAL 또는 JTA 트랜잭션이 환경 구성을 기반으로합니다.

    #getCurrentSession () 호출로 인해 문제가 발생했습니다.

    Spring은 EntityManager를 생성하고, #getCurrentSession ()을 호출 할 때 메소드 내부에서 @Transactional 어노테이션에 의해 시작된 트랜잭션에 바인딩되지 않은 두 번째 세션을 생성하도록 Hibernate에 요청합니다. 간단히 요약하면 다음과 같습니다.

    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    Session aNewSession = entityManager.unwrap( Session.class )
      .getFactory()
      .getCurrentSession();
    // at this point entityManager is scoped to a transaction
    // aNewSession is not scoped to any transaction
    // this also likely uses 2 connections to the database which is a waste
    

    위에서 언급 한 패러다임을 따라 가면 더 이상 문제가 발생하지 않아야합니다. Spring 환경에서 EntityManager 인스턴스를 적절하게 삽입 할 수있게하려면 Spring 환경에서 #getCurrentSession () 또는 #openSession ()을 호출 할 필요가 없다.

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

    2.스프링 부트 응용 프로그램을 WebLogic Server에 배포 할 때도 동일한 오류가 발생합니다. (심지어 Eclipse (Tomcat에 배포)를 통해 직접 실행하는 경우에도 작동합니다.)

    스프링 부트 응용 프로그램을 WebLogic Server에 배포 할 때도 동일한 오류가 발생합니다. (심지어 Eclipse (Tomcat에 배포)를 통해 직접 실행하는 경우에도 작동합니다.)

    UserService에 @EnableTransactionManagement를 추가하여 문제를 해결했습니다.

  3. from https://stackoverflow.com/questions/50650041/spring-boot-hibernate-no-transaction-is-in-progress by cc-by-sa and MIT license