환경: java17, spring boot 3.1.5, spring batch 5.0.3, mysql5.7
이슈:
아래 에러가 간헐적으로 발생하며 배치 실패. 재실행 시 정상 처리
Caused by: com.mysql.cj.jdbc.MysqlXAException: XAER_DUPID: The XID already exists
at com.mysql.cj.jdbc.MysqlXAConnection.mapXAExceptionFromSQLException(MysqlXAConnection.java:344)
at com.mysql.cj.jdbc.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:329)
at com.mysql.cj.jdbc.MysqlXAConnection.start(MysqlXAConnection.java:290)
at com.atomikos.datasource.xa.XAResourceTransaction.resume(XAResourceTransaction.java:217)
... 81 common frames omitted
Caused by: java.sql.SQLException: XAER_DUPID: The XID already exists
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:130)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:763)
at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:648)
at com.mysql.cj.jdbc.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:323)
디비에서 xa recover; 로 검색 시 남아있는 트랜젝션 없는 것 확인
해결:
XID 중복이라 우선 XID가 어떻게 생성되는지 확인
-
gtrid (Global Transaction ID): 분산 트랜잭션을 식별하는 고유한 값
-
bqual (Branch Qualifier): 트랜잭션 내에서 개별 브랜치를 구분하는 값
16진수 → ASCII 디코딩
제공된 XID는 16진수(Hex)로 인코딩 되어 있음. 이를 ASCII 문자로 변환해야 함
XID: 172.18.0.3.tm174046320874700011:172.18.0.3.tm11
XID: <IP>:tm<TIMESTAMP>:<BRANCH_ID>
gtrid = 172.18.0.3.tm174046320874700011
bqual = 172.18.0.3.tm11
- 172.18.0.3 → 트랜잭션을 실행한 클라이언트 서버의 IP(여기서는 배치 서버)
- tm174046320874700011 → 글로벌 트랜잭션 ID (gtrid)
- 174046320874700011 → 타임스탬프 기반의 유니크 ID
- tm11 → 브랜치 ID (bqual)
XID에 배치 서버 ip와 timestamp가 들어가므로 해당 서버에서 그 시간에 동시에 돌았던 'jta transaction'과 연관이 있었을 것으로 생각..
그걸 확인하기 위해 xid에 프로젝트 명이나 job 이름을 넣어보기로 했다.
상수 값도 줄 수 있고 아래처럼 spel을 사용하여 동적으로 줄 수도 있다.
spring.jta.atomikos.properties.transaction-manager-unique-name=${TRANSACTION_MANAGER_NAME:defaultTxManager}
- 설정 대상: Atomikos 전체 트랜잭션 관리자
- 역할: 트랜잭션 관리자(Transaction Manager)의 고유한 이름 지정
- 사용 위치: 전역적으로 하나만 설정 (애플리케이션 전체에서 단 하나)
- 중복되면 안 됨: 동일 네트워크 내 여러 인스턴스에서 서로 다른 값 필요
우선 해당 시간에 돈 배치 중 jta transaction 을 사용하는 배치는 이 배치 밖에 없을 것 같고
그래서 중복이 나도 한 프로젝트 안에서, 특히 이 job 안에서 발생했을 것 같긴 한데
우선 그걸 확증하기 위해 위와 같은 설정을 추가해 본다.
그래도 나면 그땐 진짜 우리끼리의 싸움
+ 그때는 XID에 UUID를 심을 수 있는 빈을 위 설정에 연결하는 게 좋을 것 같다.
추가로
spring.jta.atomikos.properties.transaction-manager-unique-name=${TRANSACTION_MANAGER_NAME:defaultTxManager}
이 설정 값과 소스의 아래 부분이 동일한 설정이라고 생각했는데.. 그것은 아니었다..
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
dataSource.setUniqueResourceName(resourceNameCreator.createResourceName(BATCH_DATASOURCE_NAME));
- 설정 대상: 특정 DataSource(XA 리소스)
- 역할: 각 XA 리소스를 식별하는 고유한 이름(Unique Name) 지정
- 사용 위치: 각각의 AtomikosDataSourceBean 객체에 대해 개별적으로 설정
- 중복되면 안 됨: 각 DataSource마다 고유해야 함 (여러 개의 XA 리소스를 사용할 경우 필수)
AtomikosDataSourceBean은 데이터 소스에 해당하는 고유 이름을 주는 것이고
transaction-manager-unique-name는 atomikos transaction manager의 고유한 이름을 지정하는 것이었다..
'개발 > spring' 카테고리의 다른 글
open feign에서 401일 때 바디가 안 나올 경우 (0) | 2025.03.11 |
---|---|
[pageImpl] 기존이랑 똑같이 페이징 시 갑자기 경고가? EnableSpringDataWebSupport (1) | 2024.12.18 |
[mvc] pathVariable String -> enum으로 자동 변환해주는 법 (1) | 2024.12.09 |
[JtaTransaction] 분산 트랜젝션 (0) | 2024.11.27 |
[jpa] Repository, CrudRepository, JpaRepository (0) | 2024.11.23 |