은행이나 금융권 개발 쪽 말을 들어보면 트랜잭션이란 말이 많이 나온다. 또 MySQL 이용자들이 InnoDB를 사용하는 가장 큰 이유도 트랜잭션을 지원하기 때문이라고도 한다. 굉장히 좋다는 건 뭔지 알겠는데 이름만 들어서는 도통 감이 안온다. 어느 정도냐면 필자가 트랜잭션이란 말을 처음 접했을 때는 트랜지스터처럼 뭔가를 쪼끄맣게 만드는 것이나 DB에서 상거래를 이용할 수 있게 하는 기술인 줄 알았다. 게다가 트랜잭션이란 코드에서 처리하는게 아니라 MySQL쿼리문만 처리가능한 기술이라고 말도 안되는 오해를 할 때도 있었다. 물론 모두 틀렸다. 트랜잭션에 대한 개념을 간략하게 설명하자면 다음과 같다.
트랜잭션은 현대의 웹 보안에 있어서 매우 중요한 역할을 차지하며 DB와 JAVA 언어가 데이터를 주고 받는 과정에 원자성을 부여하는 수단을 일컫는다.
트랜잭션에 대해 잘 모르는 독자들은 이 말만 들어서는 트랜잭션이 뭔지 감이 안올 수도 있을 것이다. 필자도 트랜잭션이 뭔지 알고 나서야 이 말의 감을 잡았지 결코 위의 글을 읽고 "트랜잭션이란 정말 좋은 기술이구나. 나도 해봐야겠다!"라고 생각하진 않았으니 말이다.
과거에 트랜잭션이란 소수의 웹개발자들만이 공유하는 기술로 인식되곤 했다. 굉장히 고급기술이고 손이 많이 가는 작업인지라 트랜잭션이 일반화되지 않았을 때는 트랜잭션과 비슷한 기술인 프로시져를 더 선호할 때도 있었다. 물론 아직도 트랜잭션보다 프로시져를 선호하는 사람들이 존재한다. 하지만 이런 발달된 프레임워크 덕분에 트랜잭션을 이용하는 방법이 쉬워졌고 트랜잭션의 장점 또한 더욱 부각되면서 자바진영에서만큼은 프로시져보다 트랜잭션을 선호하는 추세이다.
그렇다면 트랜잭션과 프로시져란 무엇일까? 우리가 데이터베이스와 힘겹게 씨름하며 개발을 해가다보면 어느 순간 도저히 쿼리 한줄로는 끝낼 수 없는 상황에 부닥치게 되는데 이런 단일 쿼리로 해결할 수 없는 로직을 처리할 때 필요한 기술이 바로 트랜잭션이다. 먼저 트랜잭션을 설명하는데 있어서 가장 훌륭한 예제인 전자상거래를 살펴보도록 하자.
위의 예제는 우리가 한줄로 처리할 수 없는 쿼리의 가장 좋은 예이다. 먼저 쇼핑몰에서 상품을 구매할 때 회원의 잔여금액이 있는지확인하고 잔여금액이 상품가격보다 많을 때 선택한 상품을 구매하는 로직으로 넘어간다. 그리고 선택한 상품의 재고가 있는지 확인하여 재고가 있다면 회원의 잔여금액을 상품가격만큼 감소시키고 로직을 종료한다.
로직만 본다면 완벽한 것 같기도 하다. 근데 만약의 상황을 가정해보자. 예를 들어 선택상품구매 로직에서 Exception()이 발생하여 상품이 없음에도 있다고 된 것이다. 또는 잔여금액이 감소하는 찰나에 서버의 전원이 나가 상품을 구매해버렸는데 회원의 잔여금액은 감소하지 않는 상황 말이다. 이런 문제는 곧바로 엄청난 비용손실을 발생시킬 것이다. 예를 바꾸어 금융권 경우는 어떨까? 은행같은 곳에서 특정 입력 시에 발생하는 오류를 크래커가 알아내어 송금을 하여도 자신의 계좌에서 돈이 차감되지 않는 사실을 알게 됬다면? 그 누구도 이런 전자상거래는 이용하고 싶지 않을 것이다.
트랜잭션이란 바로 이런 문제를 해결하기 위해 탄생한 기술력이다. 2개 이상의 쿼리를 하나의 커넥션으로 묶어 DB에 전송하고 이 과정에서 어떠한 에러가 발생할 경우 자동으로 모든 과정을 원래 상태로 돌려놓는다. 그야 말로 All Or Nothing 전략이다. 프로시져도 같은 맥락이긴 하지만 차이점은 로직을 Java에서 처리하는게 아니라 DB상에서 처리한다. 과거 트랜잭션 구현이 어렵고 프로시져 구현이 더 간편했을 때만 하더라도 많은 웹어플리케이션이 비지니스 로직을 Java가 아니라 DB에서 처리하는게 유행했던 시절도 있었다.
좀 황당한 사실이긴 하지만 진짜다. 혹자는 이 때는 일컬어 자바의 암흑기라고도 한다. 자바 프로그래머들이 고작 하는 거라곤 DBA(DataBase Administrator)가 짜준 로직을 호출하고 결과값을 대충 조작해 리턴해주는게 대부분이었다. 이런 개발 방식에서는개발자가 DBA님을 상전 받들 듯이 모셔야 하며 모든 로직을 구현하는데 있어 DBA님이 선사하신 프로시져를 감사한 마음으로 사용하다가 만에 하나 오류가 발생하면 이게 프로시져의 문제인지 내 코드의 문제인지 밤잠설치며 고민하다가 은근슬쩍 DBA님에게 커피라도 한잔 마치면서 넌지시 물어봐야 했던 것이다.
심지어 현장에 투입된 신입프로그래머들은 웹어플리케이션마다 제각각으로 짜진 난해한 프로시져들을 완전히 습득하기 전엔 키보드에 손도 못올릴 때가 있었다. 그 뿐이던가. 초기에 가난한 벤쳐회사가 MySQL을 이용해 서비스를 하다가 어느 정도 성장해 Oracle 같은 유료 데이터베이스로 교체할 때, 또는 하나의 웹어플리케이션에 2개 이상의 데이터베이스를 사용할 때에는 그야말로 개발자와 DBA가 서로 멱살을 움켜지며 매일같이 댄싱파티를 열어대는 장관이 연출될 때도 있었다.
왜냐하면 자바는 mysql 커넥터에서 oracle 커넥터로 라이브러리만 교체해주면 그만이지만 DBA들은 기존의 DB에 있는 프로시져들을 몽땅 새로운 DB에 옮겨 주어야 했기 때문이다. 게다가 옮기는 과정에서 생기는 오타나 데이터베이스 제품마다 다른 성질로 발생하는 문제까지 테스트 하자면 개발자들은 연이어 발생하는 트러블 때문에 모든 다시 코드를 뜯어봐야 했고 수정해주어야만 했다.
그러나 이제 트랜잭션 기술의 발달로 이런 문제는 옛날 일이 되었다. 물론 프로시져가 트랜잭션보다 속도가 빠르다는 이유로 아직도 프로시져를 사용하는 그룹이 있긴 하다. 하지만 서버의 퍼포먼스 향상과 기술이 발달로 그런 속도차는 극단적인 상황이 아닌 이상 미미한게 사실이다.
다시 본론으로 돌아가자면 트랜잭션은 하나 이상의 쿼리에서 동일한 Connection 객체를 공유하는 것을 뜻한다. 이게 뭔말인가 하면 Java에서 DB로 연결할 때는 java.sql.Connection이란 객체를 이용하는데 이 Connection 객체에는 setAutoCommit(자동커밋)이라는 메서드가 존재한다. 이 메서드와 연결된 autoCommit 객체는 true란 기본값을 가지고 있으며 한번의 연결 이후 자동으로 커넥션을 커밋해 종료시켜준다. 근데 트랜잭션을 이용하려면 이 자동커밋을 false로 바꾸고 수동커밋으로 변경해야만 한다. 즉 이용자가 직접 커넥션에 대해 커밋과 롤백을 해준다는 뜻이다.
Commit(커밋) : 해당 Connection의 요청을 완료하고 특별한 에러가 없다면 결과를 DB에 반영한다.
RollBack(롤백) : 해당 Connection 수행 중 예기치 않은 에러가 발생하였다면 모든 과정을 취소하고 DB를 Connection이 수행되기 이전상태로 변경한다.
물론 스프링의 트랜잭션 기술을 이용하면 이런 과정을 직접 해줄 필요는 없다. 스프링은 단 몇줄의 코드만으로 다이나믹 프록시와 AOP라는 기술을 통해 크게는 인터페이스 단위에서 클래스, 작게는 메서드까지 세분화하여 트랜잭션을 컨트롤할 수 있게 한다. 거기다 애노테이션 기술로 @Transactional을 설정하는 것만으로도 메서드 또는 클래스, 인터페이스까지 트랜잭션 설정이 가능하게 해준다.
우리는 여러 오픈소스 개발자들의 노력 덕분에 트랜잭션을 편리하게 이용할 수 있게 됬으며 금융권, 상거래에도 문제없이 비지니스 로직의 주도권을 찾아올 수 있게 되었다. 다음 장에서는 본격적으로 스프링의 트랜잭션에 대해 다뤄보도록 하겠다. 마지막으로 덧붙이자면 우리가 이처럼 트랜잭션 쉽게 구현할 수 있고 또 이용할 수 있다면 이젠 트랜잭션도 선택이 아닌 필수 사항이 되어야만 한다. 감당할 수 있는 에러라도 발생하지 않도록 하는 것이 가장 현명한 처사 아니겠는가!
* 공유 : http://springmvc.egloos.com/495798 (문제시 삭제하겠습니다.)
'Programming > java' 카테고리의 다른 글
Windows10 open JDK 설치하기 (1) | 2018.11.06 |
---|---|
SSL 적용하기 (0) | 2018.07.25 |
SMTP 이메일 보내기 (0) | 2018.03.23 |
[java] SSLHandshakeException (0) | 2017.06.16 |
c#과 java 차이 (4) | 2015.03.04 |