Oracle Sequence를 활용하여 Primary Key를 사용하는 케이스가 종종 있는데, JAVA Spring Multi Thread 환경에서 해당 시퀀스가 동시성 이슈가 발생하지 않고, 정상적으로 Insert가 되는지 간단하게 테스트를 진행한 내용 정리를 해보도록 하겠습니다. 테스트는 스프링부트 + Mybatis 환경에서 진행을 하였습니다.
테스트 환경
테스트를 위해 mId 컬럼이 PK인 MEMBERS라는 간단한 테이블을 생성해 줍니다. 그리고 MDISEQ라는 시퀀스도 생성을 해줍니다.
CREATE TABLE MEMBERS
(
mId NUMBER(4) NOT NULL,
name VARCHAR2(10),
age NUMBER(4),
CONSTRAINT mId_pk PRIMARY KEY (mId)
);
그리고 실패하는 비교 케이스를 위해, mID의 Max값에 +1을 해줘서 PK값을 만들고 insert하는 쿼리와 시퀀스를 이용하여 PK값을 만들어 insert 쿼리를 아래와 같이 생성합니다.
Mapper.xml
<insert id="setMemberUsingSubQuery" parameterType="com.example.demo.vo.Member">
INSERT INTO MEMBERS ( mID, name, age )
VALUES (
( SELECT TO_NUMBER( MAX( mID ) ) + 1 FROM MEMBERS )
,#{name}
,#{age}
)
</insert>
<insert id="setMemberUsingSequence" parameterType="com.example.demo.vo.Member">
INSERT INTO MEMBERS ( mID, name, age )
VALUES (
MIDSEQ.NEXTVAL
,#{name}
,#{age}
)
</insert>
Service.java
@Slf4j
@Service
@RequiredArgsConstructor
public class DemoService {
private final DemoMapper demoMapper;
public void setMemberUsingSubQuery (Member member) {
log.info(member.getName());
demoMapper.setMemberUsingSubQuery(member);
}
public void setMemberUsingSequence (Member member) {
demoMapper.setMemberUsingSequence(member);
}
}
테스트
위의 두 쿼리 모두 동일하게 멀티쓰레드 2개를 생성하고 쿼리를 수행합니다.
@SpringBootTest
class DemoApplicationTests {
@Autowired
DemoService demoService;
@Test
@Transactional
void 서브쿼리로_키값_생성() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Member m1 = new Member( "Kim", 10 );
Member m2 = new Member( "Lee" , 20 );
CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> { demoService.setMemberUsingSubQuery(m1); }, executorService);
CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> { demoService.setMemberUsingSubQuery(m2); }, executorService);
CompletableFuture.allOf(cf1, cf2).join();
}
@Test
@Transactional
void 시퀀스로_키값_생성() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Member m1 = new Member( "Kim", 10 );
Member m2 = new Member( "Lee" , 20 );
CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> { demoService.setMemberUsingSequence(m1); }, executorService);
CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> { demoService.setMemberUsingSequence(m2); }, executorService);
CompletableFuture.allOf(cf1, cf2).join();
}
}
결과
서브쿼리로 키값을 생성하는 경우에는 "unique constraint violated" 키 값이 중복되는 에러가 발생하였지만, 시퀀스를 이용한 쿼리는 정상적으로 수행이 되었습니다.
반응형
'[IT] DB' 카테고리의 다른 글
[Oracle DB] 성능 테스트를 위한 랜덤 데이터 생성하기 (DBMS_RANDOM) (0) | 2023.01.31 |
---|---|
Windows OS - ORACLE DB 다운로드 및 설치 (INS-30014 오류 해결) (0) | 2023.01.10 |
[H2 Database] H2 Database 설치 (0) | 2021.10.20 |
[Maria DB] Windows에 DB 설치 및 Database 생성, User 생성 및 권한 설정 (0) | 2021.08.02 |
댓글