트랜잭션
- Transaction : 한번에 수행되어야 하는 작업의 논리적인 단위
가게에서 물건을 구입한다면 가게 입장에서는 물건을 주고 금액을 받아야 한다.
고객 입장에서 보면 금액을 지불하고 물건을 받아야 한다.
데이터베이스 입장에서 보면 가게는 금액을 수정하고 물건에 대한 정보를 수정해야 한다.
가게 입장에서는 2개의 SQL 구문이 수행되어야 한다.
고객 입장에서보면 금액이 수정되어야 하고 물건에 대한 정보도 수정되어야 한다.
고객 입장에서도 2개의 SQL 구문이 수행되어야 한다.
Dao가 SQL을 4개를 실행해야 한다.
이 경우 하나의 SQL 수행이 성공했다고 commit을 해버리면 잘못된 결과가 저장될 수 있다.
이런 경우는 4개의 SQL이 모두 성공한 경우만 성공이고 나머지 경우는 실패라서 초기상태로 되돌려야 한다.
이렇게 한꺼번에 수행되어야 하는 SQL을 하나로 묶은 것을 트랜잭션 이라고 한다.
1. 트랜잭션 처리 방식
1) manual commit
- 직접 commit과 rollback을 수행
2) auto commit
- 하나의 sql 구문이 성공적으로 수행되면 자동으로 commit을 수행 ( 굉장히 위험하다)
- java의 JDBC 와 MyBatis는 근본적으로 auto commit 이다.
2. MyBatis 에서의 트랜잭션 처리(manual commit 사용)
- 스프링 설정 파일에서 트랜잭션 매니저 객체를 생성
<bean class="org.springframework.jdbc.datasouce.DataSourceTransactionManager" id="transactionManager">
<property came="dataSource" ref="DataSourceID"/>
</bean>
트랜잭션 관리를 annotation으로 할 수 있도록 해주는 객체를 생성
<tx:annotation-driven transaction-manager="앞에서 만든 bean의 id"/>
메소드 위에
@Transactional
을 추가하면 메소드 수행 도중 예외가 발생하면 rollback 하고 예외가 발생하지 않으면 commit을 수행해 준다.트랜잭션은 Dao 클래스에 적용하는 것이 아니고 Service 나 Controller에 적용해야 한다.
3.MyBatis의 트랜잭션 처리 실습
1) Service 클래스를 생성
- db.mybatis.service.GoodService
package db.mybatis.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import db.mybatis.dao.GoodDao;
import db.mybatis.domain.Good;
@Service // 이클래스의 bean은 자동 생성
public class GoodService {
// 동일한 자료형의 bean이 있으면 자동으로 주입해주는 어노테이션
@Autowired
private GoodDao goodDao;
// 데이터를 삽입하는 메소드
public int insertGood(Good good) {
// 동일한 데이터를 2번 삽입 - 예외발생
goodDao.insertGood(good);
return goodDao.insertGood(good);
}
}
2) 스프링 설정 파일에 GoodService 인스턴스를 자동 생성하도록 설정
- context 네임스페이스 추가
- 코드 추가 - applicationController.xml
<!-- 어노테이션 설정을 사용할 수 있도록 해주는 태그 -->
<context:annotation-config/>
<!-- bean 자동생성 패키지 등록 -->
<context:component-scan base-package="db"/>
3) main을 수정 하고
package db.mybatis;
import java.util.List;
import org.springframework.context.support.GenericXmlApplicationContext;
import db.mybatis.dao.GoodDao;
import db.mybatis.domain.Good;
import db.mybatis.service.GoodService;
public class MyBatisMain {
public static void main(String[] args) {
GenericXmlApplicationContext context =
new GenericXmlApplicationContext(
"classpath:applicationController.xml");
Good good = new Good();
good.setCode(101);
good.setName("무화가");
good.setManufacture("모름");
good.setPrice(3000);
GoodService service = context.getBean(GoodService.class);
service.insertGood(good);
context.close();
}
}
- service 의 insertGood은 동일한 데이터를 2번 삽입하는 메소드 이다.
- 동일한 code를 2번 삽입할려고 해서 첫번째 데이터는 정상적으로 삽입이 되고 두번째 삽입하려고 할때 예외가 발생 한다.
- 트랜잭션을 적용하지 않아서 auto-commit 입니다.
- 첫번째 데이터가 삽입하는데 성공하면 워본 데이터베이스에 반영하고 두번째 sql을 실행한다.
- 첫번째 데이터는 삽입에 성공하고 두번째 삽입은 실패한다.
4) 스프링 설정 파일에 mybatis 트랜잭션 적용을 위한 bean을 생성
- tx 네임스페이스 추가
- 코드 추가 - applicationController.xml
<!-- MyBaits 트랜잭션 적용을 위한 클래스의 객체 생성 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 트랜잭션을 어노테이션으로 설정하기 위한설 -->
<tx:annotation-driven transaction-manager = "transactionManager"/>
5) Service 메소드에 트랜잭션 추가
package db.mybatis.service;
@Service // 이클래스의 bean은 자동 생성
public class GoodService {
// 동일한 자료형의 bean이 있으면 자동으로 주입해주는 어노테이션
@Autowired
private GoodDao goodDao;
// 데이터를 삽입하는 메소드
@Transactional //Manual Commit이 적용되고 메소드 수행도중 예외가 발생하면 rollback
public int insertGood(Good good) {
// 동일한 데이터를 2번 삽입 - 예외발생
goodDao.insertGood(good);
return goodDao.insertGood(good);
}
}
6) main 메소드를 수정하고 실행
package db.mybatis;
public class MyBatisMain {
public static void main(String[] args) {
GenericXmlApplicationContext context = new GenericXmlApplicationContext("classpath:applicationController.xml");
Good good = new Good();
good.setCode(103);
good.setName("무화가");
good.setManufacture("모름");
good.setPrice(3000);
GoodService service = context.getBean(GoodService.class);
service.insertGood(good);
context.close();
}
}
- 실행하면 두번째 삽입을 수행하다가 예외가 발생하면 첫번째 삽입은 성공했지만 하나의 트랜잭션으로 묶여있어서 같이 취소됩니다.
- 결과 : 트랜잭션 을 넣지 않을 때는 에러가 나면서도 데이터베이스에 데이터가 삽입(commit)되었는데 , 트랜잭션을 넣었더니 데이터가 안들어가고 데이터베이스에 데이터가 안들어가더라 (rollback)