2019. 10. 24. 00:20ㆍSpring
지난번에 Spring에서 Email을 이용해 회원가입 인증 메일전송을 구축했습니다.
기능을 구현중 뜻하지 않은 버그가 발생했습니다.
당시 mailConfig 파일을 설정 중 smtp 계정을 바르게 입력하지 않아 mailAuthenticationException가 발생했습니다.
만약에 회원가입 submit버튼 클릭시 위와같은 에러가 나게 된다면 메일을 전송하지 않게 되므로 db에 회원가입시 기입했던 정보들을 insert처리하지 말아야합니다.
하지만 이와 관계없이 정보는 db에 insert처리된것을 확인 할 수 있었습니다.....
이러한 것을 막기 위해 우리는 트랜잭션이라는 기능을 수행해줘야합니다.
트랜잭션
트랜잭션을 쉽게 설명하자면 한꺼번에 수행되야하는 일련의 연산이라고 합니다.
전부 OK 거나 전부 NO 라고 할 수 있지요.
예를들어 입사지원과 마찬가지라고 생각할 수 있습니다.
서류전형 -> 필기 -> 면접 -> 합격 이라는 과정이 있습니다.
이들중에 한개라도 통과되지 않는다면 회사에 입사했다고 할 수 있을까요? 당연히 아니지요.
트랜잭션은 이와 마찬가지입니다.
트랜잭션 의 모든 연산은 반드시 한꺼번에 완료가 되야 하며 그렇지 않은경우에는 한꺼번에 취소되어야 하는 원자성을 가지고 있습니다
한꺼번에 완료가 된경우에는 성공적인 종료 COMMIT 이라하며 이 경우에는 작업결과는 데이터베이스에 반영이 되게 됩니다.
취소가 된경우에는 비정상적인 종료 ROLLBACK 이라 하며 이 경우에 작업결과는 모두 취소되게 되어 데이터베이스에 영향을 미치지 않게 됩니다.
트랜잭션은 아래와 같은 성질을 가지고 있고 반드시 이 성질을 지켜야 합니다.
< 트랜잭션의 성질 >
원자성(Atomicity) | - 분리 할수 없는 하나의 단위로 작업은 모두 완료되거나 모두 취소 되어야 합니다. |
일관성(Consistency) | 사용되는 모든 데이터는 일관되어야 합니다. |
격리성(Isolation) |
- 접근하고 있는 데이터는 다른 트랜잭션으로 부터 격리 되어야 합니다. - 트랜잭션이 진행되기전과 완료된 후에 상태를 볼수 있지만 트랜잭션이 진행되는 중간 데이터는 볼수 없습니다. |
영속성(Durability) | - 트랜잭션이 정상 종료되면 그 결과는 시스템에 영구적으로 적용되어야 합니다. |
순차성(Sequentiality) | - 데이터를 다시 로드하고 트랜잭션을 재생하여 원래 트랜잭션이 수행된 후의 상태로 데이터를 되돌리는 것을 말합니다. |
따라서 우리는 메일전송 완료시 정보가 commit 되고 그렇지 않을경우에 rollback을 시켜주는 트랜잭션 처리단위를 만들어줘야 합니다.
코드
<DispatcherServlet.xml>
<!-- Transaction -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">
</property>
</bean>
<tx:annotation-driven />
우선 dispatcherServlet에 transaction bean 정보를 추가해줍니다.
<UserServiceImpl>
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor={Exception.class})
public void createByUser(UserVO userVO) throws Exception {
uDAO.createByUser(userVO);
String authKey = new TempKey().getKey(8, false);
userVO.setAuthkey(authKey);
uDAO.updateAuthKey(userVO);
// mail 작성 관련기능
MailUtils sendMail = new MailUtils(mailSender);
sendMail.setSubject("[Jihye's CRUD] 회원가입 이메일 인증");
sendMail.setText(new StringBuffer().append("<h1>[이메일 인증]</h1>")
.append("<p>아래 링크를 클릭하시면 이메일 인증이 완료됩니다.</p>")
.append("<a href='http://localhost:8090/user/joinConfirm?uid=")
.append(userVO.getUid())
.append("&email=")
.append(userVO.getEmail())
.append("&authkey=")
.append(authKey)
.append("' target='_blenk'>이메일 인증 확인</a>")
.toString());
sendMail.setFrom("altjd815@gmail.com ", "Lee Ji-Hye");
sendMail.setTo(userVO.getEmail());
sendMail.send();
}
Service부분에 트랜잭션을 추가해줬습니다. 코드를 살펴보자면 다음과 같습니다.
1. 트랜잭션을 설정할 메소드에 @Transactional이라는 어노테이션을 추가해줍니다.
2. 트랜잭션의 Propagation를 보면 전파 속성을 지정할 수 있다. 기본값인 Propagation.REQUIRED 로 지정해 트랜잭션이 없을 시에 새로 만들어주도록 설정했습니다.
3. Exception 발생 시 , rollback처리를 실행시켜주기 위해 rollbackFor={Exception.class} 옵션을 추가해줍니다.
위와같이 설정 한 후, 에러를 발생시켜 메일전송을 해봤습니다.
짜잔~~ 에러가 발생시 rollback을 수행해 정보들이 db에 insert되지 않은 것을 확인했습니다.
위와같은 과정으로 트랜잭션에 대해서 알아 볼 수 있었습니다.
문득 트랜잭션을 알고나니 제 코드에 완벽하지 않은 점을 또하나 발견할 수 있었습니다.
만약에 아이디와 이메일을 중복검사 한 후 전송버튼을 누르는 그 짧은 텀에 누군가가 아이디 혹은 이메일을 먼저 선점했다면 어떻게될까요??
테이블에 unique나 primarykey설정을 했다면 error가 발생해 수행이 되지않겠지만 이경우가 아닐경우 db에 정보가 그대로 insert되어 중복 아이디, 이메일이 설정됐을겁니다....
이와같은 경우에도 트랜잭션 설정해야 되겠지요.... 여러가지를 알고나니 머리가 매우 복잡해집니다 ㅜㅜ
'Spring' 카테고리의 다른 글
#3. Intellij와 AWS를 이용한 웹사이트 구축 :: WAR EXPORT 및 업로드 (0) | 2019.10.25 |
---|---|
#2. Intellij와 AWS를 이용한 웹사이트 구축 :: IntelliJ에서 SSH연결하기 (0) | 2019.10.25 |
#1. Intellij와 AWS를 이용한 웹사이트 구축 :: AWS설정 (0) | 2019.10.25 |
[Spring email]Intellij Spring 이메일 보내기 :: 회원가입 SMTP 인증 메일 전송 (1) | 2019.10.19 |