programing

Spring JPA(Hibernate) Entity Manager와의 연결 풀에 연결이 반환되는 시기는 언제입니까?

lastcode 2023. 8. 5. 10:17
반응형

Spring JPA(Hibernate) Entity Manager와의 연결 풀에 연결이 반환되는 시기는 언제입니까?

Java 프로세스에서 다음 스프링 구성을 사용하여 MySql에 연결합니다.

@Configuration
@EnableTransactionManagement
@PropertySources({ @PropertySource("classpath:/myProperties1.properties"), @PropertySource("classpath:/myProperties2.properties") })
public class MyConfiguration {

    @Autowired
    protected Environment env;

    /**
     * @return EntityManagerFactory for use with Hibernate JPA provider
     */
    @Bean(destroyMethod = "destroy")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setJpaVendorAdapter(jpaVendorAdapter());
    em.setPersistenceUnitManager(persistenceUnitManager());

    return em;
    }

    /**
     * 
     * @return jpaVendorAdapter that works in conjunction with the
     *         persistence.xml
     */
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setDatabase(Database.valueOf(env.getProperty("jpa.database")));
    vendorAdapter.setDatabasePlatform(env.getProperty("jpa.dialect"));
    vendorAdapter.setGenerateDdl(env.getProperty("jpa.generateDdl", Boolean.class, false));
    vendorAdapter.setShowSql(env.getProperty("jpa.showSql", Boolean.class, false));

    return vendorAdapter;
    }

    @Bean
    public PersistenceUnitManager persistenceUnitManager() {
    DefaultPersistenceUnitManager pum = new DefaultPersistenceUnitManager();
    pum.setPackagesToScan("com.app.dal");
    pum.setDefaultPersistenceUnitName("my-pu");
    pum.setPersistenceXmlLocations("classpath:/META-INF/persistence.xml");
    pum.setDefaultDataSource(dataSource());

    return pum;
    }

    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
    Properties dsProps = new Properties();
    dsProps.put("driverClassName", env.getProperty("hikari.driverClassName"));
    dsProps.put("username", env.getProperty("hikari.username"));
    dsProps.put("password", env.getProperty("hikari.password"));
    dsProps.put("jdbcUrl", env.getProperty("hikari.source.data.jdbcUrl"));
    dsProps.put("connectionTimeout", env.getProperty("hikari.connectionTimeout", Integer.class));
    dsProps.put("idleTimeout", env.getProperty("hikari.idleTimeout", Integer.class));
    dsProps.put("maxLifetime", env.getProperty("hikari.maxLifetime", Integer.class));
    dsProps.put("maximumPoolSize", env.getProperty("hikari.maximumPoolSize.rtb.source", Integer.class));
    dsProps.put("leakDetectionThreshold", env.getProperty("hikari.leakDetectionThreshold", Integer.class));
    dsProps.put("jdbc4ConnectionTest", env.getProperty("hikari.jdbc4ConnectionTest", Boolean.class));

    HikariConfig config = new HikariConfig(dsProps);
    HikariDataSource ds = new HikariDataSource(config);

    return ds;
    }

    @Bean(name = "sourceTxMgr")
    public PlatformTransactionManager sourceDatatransactionManager() {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setPersistenceUnitName("my-pu");
    transactionManager.setDataSource(dataSource());

    return transactionManager;
    }

    @Bean
    public PersistencyManager persistencyManager() {
    return new JpaPersistencyManager();
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
    }

}

Entity-Manager는 컨테이너에 의해 데이터 액세스 계층에 주입됩니다.

@PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "my-pu")
private EntityManager myEntityManager;

그리고 제 퍼블릭 비즈니스 논리 방식은 다음과 같은 주석이 달렸습니다.@Transactional 주석

내가 이해하기로는 컨테이너는 트랜잭션이 완료되면 엔티티 관리자가 풀(나의 경우 HikariCP)에 연결을 반환하도록 보장할 책임이 있지만 연결이 관리되는 방법을 설명하는 공식 문서를 찾지 못했습니다.이러한 구성을 사용할 때 정확히 언제 연결이 풀로 반환되는지 설명할 수 있는 좋은 참조 자료를 제공할 수 있는 사람이 있습니까?

업데이트:

지금까지 생각해 낸 가장 관련된 정보(여기서 발췌):

EntityManager를 구현하는 지속성 컨텍스트 프록시는 선언적 트랜잭션 관리를 수행하는 데 필요한 유일한 구성 요소가 아닙니다.실제로 세 가지 개별 구성 요소가 필요합니다.

EntityManager Proxy 자체 트랜잭션 측면 트랜잭션 관리자 각 항목을 살펴보고 이들이 어떻게 상호 작용하는지 살펴보겠습니다.

트랜잭션 측면

트랜잭션 측면은 주석이 달린 비즈니스 방법 앞과 뒤에 모두 호출되는 '주변' 측면입니다.측면을 구현하기 위한 구체적인 클래스는 트랜잭션입니다.요격기.

트랜잭션 측면에는 두 가지 주요 책임이 있습니다.

'이전' 시점에서 이 측면은 호출하려는 비즈니스 방법이 진행 중인 데이터베이스 트랜잭션의 범위에서 실행되어야 하는지 또는 새로운 별도 트랜잭션을 시작해야 하는지 여부를 결정할 수 있는 후크 포인트를 제공합니다.

'이후' 순간에는 트랜잭션을 커밋할지, 롤백할지, 계속 실행할지를 결정해야 합니다.

트랜잭션 측면 자체에 의사결정 로직이 포함되어 있지 않은 '이전' 시점에서 필요한 경우 새로운 트랜잭션을 시작하기로 한 결정은 트랜잭션 관리자에게 위임됩니다.

트랜잭션 관리자

트랜잭션 관리자는 다음 두 가지 질문에 대한 답변을 제공해야 합니다.

새 엔터티 관리자를 만들어야 합니까?새로운 데이터베이스 트랜잭션을 시작해야 합니까?이는 트랜잭션 측면의 '이전' 논리가 호출되는 순간에 결정되어야 합니다.트랜잭션 관리자는 다음을 기준으로 결정합니다.

하나의 트랜잭션이 이미 진행 중이거나 트랜잭션 메서드의 전파 속성이 아님(예: REQUEST_NEW는 항상 새 트랜잭션을 시작함) 트랜잭션 관리자가 새 트랜잭션을 만들기로 결정하면 다음과 같이 됩니다.

새 엔터티 관리자 만들기 엔터티 관리자 바인딩을 현재 스레드에 DB 연결 풀에서 연결 가져오기 엔티티 관리자와 연결은 모두 스레드로컬 변수를 사용하여 현재 스레드에 바인딩됩니다.

트랜잭션이 실행되는 동안 스레드에 저장되며, 더 이상 필요하지 않을 때 정리하는 것은 트랜잭션 관리자의 몫입니다.

현재 엔터티 관리자 또는 연결이 필요한 프로그램의 모든 부분은 스레드에서 검색할 수 있습니다.정확히 이를 수행하는 프로그램 구성 요소 중 하나가 EntityManager 프록시입니다.

전혀 복잡하지 않습니다.

  1. 첫째, Spring 트랜잭션 관리자는 트랜잭션 관리 추상화에 불과하다는 것을 이해해야 합니다.이 경우 실제 트랜잭션은 JDBC 연결 수준에서 발생합니다.

  2. 든모.@Transactional 호출은 다서메호에의가니됩로기채에 .TransactionInterceptor측면.

  3. TransactionIntreceptor트랜잭션 관리를 현재 구성된 구현에 위임(JpaTransactionManager당신의 경우).

  4. JpaTransactionManager현재 실행 중인 Spring 트랜잭션을 EntityManager에 바인딩하여 현재 트랜잭션에 참여하는 모든 DAO가 동일한 지속성 컨텍스트를 공유합니다.

  5. JpaTransactionManager 단히사다니합을 합니다.EntityManager트랜잭션 제어를 위한 트랜잭션 API:

     EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
     tx.commit();
    

JPA 트랜잭션 API는 기본 JDBC 연결 커밋/롤백 메서드에 호출을 위임합니다.

  1. ),org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction 전화 번호:

     transactionCoordinator().getTransactionContext().managedClose();
    

최대 절전 모드 세션(Entity Manager) 종료를 트리거합니다.

  1. 따라서 기본 JDBC 연결도 트리거되어 닫힙니다.

     jdbcCoordinator.close();
    
  2. 최대 절전 모드에는 논리적 JDBC 연결 핸들이 있습니다.

     @Override
     public Connection close() {
         LOG.tracev( "Closing JDBC container [{0}]", this );
         if ( currentBatch != null ) {
         LOG.closingUnreleasedBatch();
             currentBatch.release();
         }
         cleanup();
         return logicalConnection.close();
     }
    
  3. 논리적 연결은 닫기 호출을 현재 구성된 연결 공급자에게 위임합니다.DataSourceConnectionProvider이 경우), 즉 JDBC 연결에 대한 닫기 메서드를 호출합니다.

     @Override
     public void closeConnection(Connection connection) throws SQLException {
          connection.close();
     }
    
  4. 다른 연결 풀링 DataSource와 마찬가지로 JDBC 연결 닫기는 단순히 연결을 풀로 되돌리고 물리적 데이터베이스 연결을 닫지 않습니다.이는 연결 풀링 DataSource가 모든 호출을 가로채는 JDBC Connection 프록시를 반환하고 연결 풀 처리 로직에 닫기를 위임하기 때문입니다.

RESOURCE_LOCAL 트랜잭션의 경우 다음과 같은 경우 속성도 설정해야 합니다.autocommit연결 풀에 의해 검사가 비활성화되었습니다.이렇게 하면 SQL 쿼리를 실행하거나 지속성 컨텍스트를 플러시하기 전에 데이터베이스 연결을 쉽게 얻을 수 있습니다.

언급URL : https://stackoverflow.com/questions/27486104/when-are-connections-returned-to-the-connection-pool-with-spring-jpa-hibernate

반응형