Atomikos JTA 제거: 로컬 트랜잭션 전환 및 관련 설정 정리
- JTA/XA 미사용으로 변경: JpaTransactionManager로 전환 - Atomikos 의존성 및 설정 제거, 관련 문서 및 주석 업데이트
This commit is contained in:
@@ -185,8 +185,9 @@ com.eactive.apim.portal/
|
||||
|
||||
설정: `config/PortalDatasourceConfiguration.java`
|
||||
- 각 데이터베이스별 별도 EntityManager
|
||||
- Atomikos JTA를 통한 분산 트랜잭션
|
||||
- 트랜잭션 로그: `/Log/eapim/portal/`
|
||||
- **JTA/XA 미사용**. EntityManagerFactory 별 로컬 트랜잭션 (`config/PortalConfigTransaction.java`)
|
||||
- `transactionManager` (@Primary) → EMS
|
||||
- `gatewayTransactionManager` → Gateway
|
||||
|
||||
### 설정 프로파일
|
||||
|
||||
@@ -359,7 +360,13 @@ return queryFactory.selectFrom(user)
|
||||
적절한 propagation과 함께 `@Transactional` 사용:
|
||||
- 기본값: `REQUIRED` (기존 트랜잭션에 참여하거나 새로 생성)
|
||||
- 읽기 전용 작업: 최적화를 위해 `@Transactional(readOnly = true)`
|
||||
- 다중 데이터베이스: Atomikos JTA가 자동으로 분산 트랜잭션 처리
|
||||
- **다중 데이터베이스: 분산 트랜잭션(JTA/XA) 없음.** EMS·Gateway 각각 독립 로컬 트랜잭션이다.
|
||||
- 무지정 `@Transactional` = EMS(`transactionManager`)
|
||||
- **Gateway 엔티티(`com.eactive.apim.gateway.*`, `com.eactive.eai.data.entity.onl.*`)를 다루는 서비스는
|
||||
`@Transactional("gatewayTransactionManager")` 를 명시**한다. 안 하면 게이트웨이 EntityManager 가
|
||||
리포지토리 호출 단위로 닫혀 지연 로딩에서 `LazyInitializationException` 이 난다
|
||||
(예: `ApiServiceService` — `ApiGroup.apiGroupApiList`).
|
||||
- 두 DB 를 한 원자 단위로 묶어야 하는 작업은 만들지 않는다. 현재 Gateway 는 조회 전용이다.
|
||||
|
||||
### 에러 처리
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ dependencies {
|
||||
// implementation project(':kjb-safedb')
|
||||
|
||||
implementation('org.springframework.boot:spring-boot-starter')
|
||||
implementation 'org.springframework.boot:spring-boot-starter-jta-atomikos'
|
||||
implementation('org.springframework.boot:spring-boot-starter-web')
|
||||
implementation('org.springframework.boot:spring-boot-starter-validation')
|
||||
|
||||
|
||||
+12
-1
@@ -22,8 +22,19 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* API 그룹(전시) 조회 서비스.
|
||||
*
|
||||
* <p>주 조회 대상 {@link ApiGroup} 은 <b>AGW(게이트웨이) 데이터소스</b> 엔티티라
|
||||
* 트랜잭션 매니저를 {@code gatewayTransactionManager} 로 지정한다. 기본
|
||||
* {@code transactionManager}(EMS) 를 쓰면 게이트웨이 EntityManager 가 리포지토리 호출 단위로
|
||||
* 닫혀 {@code ApiGroup.apiGroupApiList} 지연 로딩에서 LazyInitializationException 이 난다.</p>
|
||||
*
|
||||
* <p>내부에서 호출하는 {@code ApiSpecInfoService} 는 EMS 쪽이며 자체 {@code @Transactional}
|
||||
* (기본 매니저)로 독립 트랜잭션을 연다. {@code ApiSpecInfo} 에는 지연 연관이 없어 문제되지 않는다.</p>
|
||||
*/
|
||||
@Service("apiServiceService")
|
||||
@Transactional
|
||||
@Transactional("gatewayTransactionManager")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ApiServiceService {
|
||||
|
||||
@@ -59,11 +59,11 @@ public class BaseDatasourceConfiguration {
|
||||
//public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings 참고
|
||||
properties.put("hibernate.dialect", prop.getHibernateDialect());
|
||||
properties.put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION");
|
||||
properties.put("hibernate.transaction.jta.platform", "org.hibernate.engine.transaction.jta.platform.internal.AtomikosJtaPlatform");
|
||||
properties.put("hibernate.physical_naming_strategy", prop.getHibernatePhysicalNamingStrategy());
|
||||
properties.put("hibernate.default_schema", prop.getSchema());
|
||||
properties.put("javax.persistence.validation.mode", "none");
|
||||
properties.put("javax.persistence.transactionType", "JTA");
|
||||
// JTA/XA 미사용. EMF 별 로컬 트랜잭션(JpaTransactionManager)으로 처리한다 - PortalConfigTransaction 참고
|
||||
properties.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
|
||||
properties.put("hibernate.format_sql", "true");
|
||||
|
||||
if (prop instanceof EmsDatasourceProperty) {
|
||||
|
||||
@@ -18,7 +18,8 @@ import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@EntityScan(basePackages = {"com.eactive.apim.gateway"})
|
||||
@EnableJpaRepositories(basePackages = "com.eactive.apim.gateway", repositoryBaseClass = BaseRepositoryImpl.class, entityManagerFactoryRef = "gatewayEntityManagerFactory")
|
||||
@EnableJpaRepositories(basePackages = "com.eactive.apim.gateway", repositoryBaseClass = BaseRepositoryImpl.class,
|
||||
entityManagerFactoryRef = "gatewayEntityManagerFactory", transactionManagerRef = "gatewayTransactionManager")
|
||||
@Slf4j
|
||||
public class GatewayDatasourceConfiguration extends BaseDatasourceConfiguration {
|
||||
private final Environment env;
|
||||
|
||||
@@ -1,39 +1,44 @@
|
||||
package com.eactive.apim.portal.config;
|
||||
|
||||
import com.atomikos.icatch.jta.UserTransactionImp;
|
||||
import com.atomikos.icatch.jta.UserTransactionManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
/**
|
||||
* 트랜잭션 매니저 설정.
|
||||
*
|
||||
* <p>EMS(포털)·AGW(게이트웨이) 두 데이터소스를 쓰지만 <b>JTA/XA 는 사용하지 않는다</b>.
|
||||
* 두 DB 를 한 트랜잭션으로 묶어 쓰는 지점이 없고(게이트웨이 측은 조회 전용),
|
||||
* 이전 Atomikos 구성도 {@code AtomikosDataSourceBean} 없이 JNDI/Hikari 데이터소스를 그대로 넘겨
|
||||
* XA 리소스가 하나도 enlist 되지 않는 형태였다. 즉 2PC 는 실제로 동작한 적이 없고
|
||||
* {@code com.atomikos.icatch.max_actives} 상한(기본 50)만 병목으로 남았다.</p>
|
||||
*
|
||||
* <p>따라서 EntityManagerFactory 별로 로컬 {@link JpaTransactionManager} 를 둔다.
|
||||
* 게이트웨이 리포지토리는 {@code GatewayDatasourceConfiguration} 의
|
||||
* {@code transactionManagerRef = "gatewayTransactionManager"} 로 연결된다.</p>
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class PortalConfigTransaction {
|
||||
|
||||
@Bean(name = "userTransaction")
|
||||
public UserTransaction userTransaction() throws SystemException {
|
||||
UserTransactionImp userTransactionImp = new UserTransactionImp();
|
||||
userTransactionImp.setTransactionTimeout(30000);
|
||||
return userTransactionImp;
|
||||
}
|
||||
|
||||
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
|
||||
public UserTransactionManager atomikosTransactionManager() {
|
||||
UserTransactionManager userTransactionManager = new UserTransactionManager();
|
||||
userTransactionManager.setForceShutdown(false);
|
||||
return userTransactionManager;
|
||||
}
|
||||
|
||||
/** EMS(포털) 기본 트랜잭션 매니저. {@code @Transactional} 무지정 시 이 매니저가 쓰인다. */
|
||||
@Primary
|
||||
@Bean(name = "transactionManager")
|
||||
@DependsOn({"userTransaction", "atomikosTransactionManager"})
|
||||
public PlatformTransactionManager transactionManager(UserTransactionManager atomikosTransactionManager) throws SystemException {
|
||||
UserTransaction userTransaction = userTransaction();
|
||||
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
|
||||
public PlatformTransactionManager transactionManager(
|
||||
@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
|
||||
return new JpaTransactionManager(entityManagerFactory);
|
||||
}
|
||||
|
||||
/** AGW(게이트웨이) 트랜잭션 매니저. {@code @Transactional("gatewayTransactionManager")} 로 지정해 쓴다. */
|
||||
@Bean(name = "gatewayTransactionManager")
|
||||
public PlatformTransactionManager gatewayTransactionManager(
|
||||
@Qualifier("gatewayEntityManagerFactory") EntityManagerFactory gatewayEntityManagerFactory) {
|
||||
return new JpaTransactionManager(gatewayEntityManagerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
spring:
|
||||
jta:
|
||||
enabled: false
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
spring:
|
||||
jta:
|
||||
enabled: false
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
spring:
|
||||
jta:
|
||||
enabled: false
|
||||
web:
|
||||
resources:
|
||||
cache:
|
||||
|
||||
@@ -58,14 +58,7 @@ spring:
|
||||
# 설정으로는 적용되지 않는다. 실제 버전닝은 PortalConfigWebDispatcherServlet 가
|
||||
# 아래 app.resource-versioning.enabled 토글을 읽어 직접 수행한다.
|
||||
|
||||
jta:
|
||||
enabled: false
|
||||
atomikos:
|
||||
properties:
|
||||
# log-base-dir: /logs/eapim/${inst.Name:devSvr11}/atomikos
|
||||
log-base-dir: /dev/null
|
||||
log-base-name: adp_tx
|
||||
max-actives: 200
|
||||
# JTA/Atomikos 제거됨. EMS·AGW 각각 로컬 트랜잭션(JpaTransactionManager) 사용 - PortalConfigTransaction 참고
|
||||
|
||||
thymeleaf:
|
||||
prefix: 'classpath:/templates/views/'
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# application.yml ? ??
|
||||
# com.atomikos.icatch.log_base_dir=/Log/eapim/portal/
|
||||
# com.atomikos.icatch.log_base_name=adp_tx
|
||||
@@ -87,9 +87,6 @@
|
||||
<logger name="org.springframework.orm.jpa" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="FILE_HIBERNATE" />
|
||||
</logger>
|
||||
<logger name="com.atomikos" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="FILE_HIBERNATE" />
|
||||
</logger>
|
||||
|
||||
<logger name="eapim.portal.session" level="INFO" additivity="false">
|
||||
<appender-ref ref="HTTP_SESSION" />
|
||||
|
||||
Reference in New Issue
Block a user