트랜잭션(transaction)이란?
데이터베이스는 다수의 사용자가 동시에 사용하더라도 항상 모순이 없는 정확한 데이터를 유지해야 한다. 그리고 데이터베이스에 장애가 발생하더라도 빠른 시간 내에 원래의 상태로 복구할 수 있어야 한다. 데이터베이스 관리 시스템은 데이터베이스가 항상 정확하고 일관된 상태를 유지할 수 있도록 다양한 기능을 제공하는데, 그 중심에는 트랜잭션이 있다. 트랜잭션이라는 것을 관리함으로써 데이터베이스의 회복과 병행 제어가 가능해져 결과적으로 데이터베이스가 일관된 상태를 유지할 수 있게 되는 것이다.
트랜잭션(transaction)은 하나의 작업을 수행하기 위해 필요한 데이터베이스의 연산들을 모아놓은 것으로, 데이터베이스에서 논리적인 작업의 단위가 된다. 트랜잭션은 장애가 발생했을 때 데이터를 복구하는 작업의 단위도 된다. 일반적으로 데이터베이스 연산은 SQL 문으로 표현되므로 트랜잭션을 작업 수행에 필요한 SQL 문들의 모임으로 이해해도 좋다.
[네이버 지식백과] 트랜잭션의 개념 (데이터베이스 개론, 2013. 6. 30., 김연희)
트랜잭션의 사용
상품을 구매할 수 있는 페이지를 구성한다고 상상하고
다음과 같은 상품관리(shop),고객계좌(client_account),주문 관리(client-order)할테이블 3개를 생성해보자.
상품구매트랜잭션은 세가지 연산으로 구성할 수 있다.
1.상품관리(shop)-상품의 재고갯수는 줄어든다.
2.고객계좌(client_account)-고객계좌의 잔고는 줄고,
3. 고객계좌의 point는 늘어난다.
만약 트랜잭션을 사용하지 않는다면 한가지 연산과정에서 에러가 났어도 다른 연산은 처리되어 문제가 될 수 있다.
ex)상품의 재고는 줄어들었으나 고객계좌의 잔고는 줄지 않는다.
Quantum-DB : 필요한 테이블 만들기
DELETE FROM shop;
DELETE FROM client_account;
CREATE TABLE shop(
num NUMBER PRIMARY KEY, --상품번호
name VARCHAR2(30), --상품이름
price NUMBER, --상품가격
remainCount NUMBER CHECK(remainCount >= 0) --재고갯수
);
-- 고객 계좌 테이블
CREATE TABLE client_account(
id VARCHAR2(30) PRIMARY KEY, -- 고객의 아이디
money NUMBER CHECK(money >= 0), -- 고객의 잔고
point NUMBER
);
-- 주문 테이블
CREATE TABLE client_order(
num NUMBER PRIMARY KEY, -- 주문번호
id VARCHAR2(30), -- 주문 고객의 아이디
code NUMBER, -- 주문한 상품의 번호
addr VARCHAR2(50) -- 배송 주소
);
-- 주문 테이블에 사용할 시퀀스
CREATE SEQUENCE client_order_seq;
-- sample 데이터
INSERT INTO shop (num,name,price,remainCount)
VALUES(1, '사과', '1000', 5);
INSERT INTO shop (num,name,price,remainCount)
VALUES(2, '바나나', '2000', 5);
INSERT INTO shop (num,name,price,remainCount)
VALUES(3, '귤', '3000', 5);
INSERT INTO client_account (id, money, point)
VALUES('superman', 10000, 0);
INSERT INTO client_account (id, money, point)
VALUES('batman', 10000, 0);
트랜잭션을 위한 환경설정
1.pom.xml에 spring-tx dependency추가
<!-- 트렌젝션 처리를 위한 라이브러리 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
servlet context의 namespaces 체크박스 설정해준다.
3.servlet context에 transaction설정을 추가한다.
beans에 명시되어있는 bean은 component-scan과 상관없이 spring에서 bean으로 관리된다.
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Transaction Manager설정 -->
<beans:bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<!-- 어노테이션으로 트렌젝션 설정이 가능하도록 -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
txManager=new DataSourceTransactionManager()'
txManager.setDataSource(dataSource);
@Transactional어노테이션을 추가한다.
@Transactional이 있는 클래스를 수행하다가 특정 exception이 발생되면 자동으로 트랜잭션관리되어 롤백된다.
트랜잭션을 붙여놨기 때문에 한가지 때문에 exception 이 발생되어도 다른 요소들도 초기화되어 적용받지 않는다.
ex)재고의 갯수가 0보다 작아져서 exception이 발생되면 10%적립도 되지않는다.
이떄 프로그래머가 임의도 exception을만들어 comstum exception을 발생 시킬 수 있다. (ex.배송 불가능한 지역입니다)
참고 https://dev-jejeb.tistory.com/50
ShopServiceImpl
//상품 구입처리를 하는 비즈니스 로직
@Transactional
@Override
public void buy(HttpServletRequest request, ModelAndView mView) {
//로그인된 아이디
String id=(String)request.getSession().getAttribute("id");
//구입할 상품번호
int num=Integer.parseInt(request.getParameter("num"));
//1. 상품의 가격정보 얻어오기
int price=shopDao.getPrice(num);
//2. 상품의 가격만큼 계좌 잔액 줄이기
ShopDto dto=new ShopDto();
dto.setId(id);
dto.setPrice(price);
dto.setNum(num);
shopDao.minusMoney(dto);
//3.가격의 10%를 포인트로 적립
shopDao.plusPoint(dto);
//4.재고의 갯수를 1 감소시킨다.
shopDao.minusCount(num);
//5.배송 요청정보를 추가한다.
OrderDto dto2=new OrderDto();
dto2.setId(id);
dto2.setCode(num);
dto2.setAddr("강남역 스타벅스");
orderDao.addOrder(dto2);
}
exception처리하기
exceptionController
class DataAccessException{
private String message:
public String getMessage(){
return this.message;
라는내용이 DataAcceessException에 들어있다.
@ExceptionHandler(DataAccessException.class)
public ModelAndView dataAccess(DataAccessException dae) {
ModelAndView mView=new ModelAndView();
//"exception"이라는 키값으로 예외객체를 담는다.
mView.addObject("exception",dae);
//view page설정
mView.setViewName("error/data_access");
return mView;
}
/error/data_access.jsp
위에서 받은 exception의 message를 받아왔다.
<div class="container">
<h1>DB관련 예외발생!</h1>
<p class="alert alert-danger">${exception.message }</p>
<a href="${pageContext.request.contextPath}/home.do">인덱스로 가기</a>
</div>
'프로그래밍 기초 > SPRING' 카테고리의 다른 글
[Spring]custom exception만들고 사용하기 /404,500에러 처리페이지만들기 (0) | 2020.02.11 |
---|---|
[Spring]게시판에 댓글 기능 구현 (1) | 2020.02.07 |
[Spring]게시물 이전글,다음글 보기 기능 구현 (0) | 2020.02.07 |
[spring]Anotation모음 (0) | 2020.02.04 |
[Spring]Mapper에서 별칭(Aliase)지정해주기 (0) | 2020.02.03 |