회원가입 시 DB에 같이 ID가 있으면 ID 뒤에 숫자를 붙여 새로운 ID를 만들어야 한다.
DB에 저장할 때 ID가 이미 DB에 저장되어 있다면 데이터 베이스는 오류 코드를 반환하고, 이 오류코드를 받은 JDBC 드라이버는 SQLException을 던진다. 그리고 SQLException에는 DB가 제공하는 errorCode라는 것이 들어있다.
(DB 벤더 마다 errorCode가 모두 다르다.)
@Slf4j
public class ExTranslatorV1Test {
Repository repository;
Service service;
@BeforeEach
void beforeEach() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
repository = new Repository(dataSource);
service = new Service(repository);
}
@Test
void duplicateKeySave() {
service.create("myId");
service.create("myId");
}
@Slf4j
@RequiredArgsConstructor
static class Service{
private final Repository repository;
void create(String memberId){
try {
repository.save(new Member(memberId, 0));
log.info("saveId = {}", memberId);
} catch (MyDuplicateKeyException e) {
log.info("키 중복, 복구 시도");
String retryId = generateNewId(memberId);
log.info("retryId = {}", retryId);
repository.save(new Member(retryId, 0));
} catch (MyDbException e) {
log.error("데이터 접근 계층 예외 ", e);
throw e;
}
}
private String generateNewId(String memberId) {
return memberId + new Random().nextInt(10000);
}
}
@RequiredArgsConstructor
static class Repository{
private final DataSource dataSource;
public Member save(Member member) {
String sql = "insert into member(member_id,money) values(?,?)";
Connection con = null;
PreparedStatement pstmt = null;
try{
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getMemberId());
pstmt.setInt(2, member.getMoney());
pstmt.executeUpdate();
return member;
} catch (SQLException e) {
//h2DB
if (e.getErrorCode() == 23505) {
throw new MyDuplicateKeyException(e);
}
throw new MyDbException(e);
}finally {
JdbcUtils.closeStatement(pstmt);
JdbcUtils.closeConnection(con);
}
}
}
}