-
Mybatis:트랜잭션_210628(월)카테고리 없음 2021. 7. 27. 16:43
Transaction ( rollback() )
>> MyBatisConfig ( 추가 )
@Configuration @EnableTransactionManagement//어노테이션 추가 @MapperScan(basePackages = {"com.stone"}) public class MyBatisConfig { // 중략.. @Bean public DataSourceTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } }
Transaction : 하나의 작업단위
예를 들어 계좌 이체라는 하나의 논리적인 작업은 총 2가지 행위로 이루어진다.
송금하는 쪽에서 출금 행위, 수신받는 쪽에선 입금 행위가 일어난다.
이 계좌이체라는 논리적 작업에서 출금만 성공하고 입금은 실패한다면 돈이 사라지는 일이 발생한다.
즉 계좌이체는 하나라도 실패하면 모든 행위가 실패하던가, 성공해야만 하는 하나의 작업단위(트랜잭션)이다.
DAO 에서 각종 sql쿼리를 수행하고 만들어진 Resultset, PreparedStatement 등의 DB관련 객체를 close하기 전에
try-catch 문의 try 블록에서 commit() 하고 예외가 발생하면 catch문에서 rollback() 하는 과정을 거친다. 이 rollback()에서 예외가 발생하면 다시
고치기 위한 코드를 try-catch 문을 사용해야 한다.
이러한 과정이 계속 반복되기 때문에 스프링에서 이를 생략할 수 있는 트랜잭션 템플릿 클래스 등을 제공한다.DataSourceTransactionManager : spring 이 관리하고 있는 객체
1) @Bean 으로 등록한다.
new 로 생성한 객체를 return 하며 MyBatis 가 사용하도록 설정한 DataSource 를 얻는 메서드를 사용해 객체를 매개변수에 넣는다.
2) @EnableTransactionManagement
Spring 의 트랜잭션매니져를 사용하기 설정@Transactional public int save(Board board) { boardMapper.saveOnlyBoard(board); attachMapper.saveAttachs(board.getAttachs()); return board.getNo(); }
@Transactional : transaction 적용
board 와 attach 를 save() 하는 두가지의 일이 담긴 하나의 트랜잭션에서 attach 가 save() 하지 못하고 예외가 났을 경우
board 까지 save() 한 것을 rollback 해준다.
+ Attach 를 Mapper 로 sql 문 역할을 하게 하고 AttachDAO 들을 없애 BoardDAO 에 대신 넣어준다.
Attach 를 BoardDAO 의 메서드에서 가져오거나 저장시 AttachMapper 로 사용하면 된다.
( IAttachDAO, AttachDAO 제거 )
>> IBoardDAO.java ( 추가 )
Attach findByAttachNo(int 첨부번호);
>> BoardDAO.java ( 추가 )
@Override public Attach findByAttachNo(int 첨부번호) { return attachMapper.findByNo(첨부번호); }
Transaction 테스트
1) @Transcational 사용시
>> mvc2.db
create table t1( col1 int primary key auto_increment, col2 int not null ); create table t2( col1 int primary key auto_increment, col2 int not null, col3 int null );
>> IT1Mapper.java
package com.stone.mvc.test_ui; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; @Mapper public interface IT1Mapper { @Insert("insert into t1(col2) values(11)") void save(); }
>> IT2Mapper.java
package com.stone.mvc.test_ui; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; @Mapper public interface IT2Mapper { @Insert("insert into t2(col3) values(111)")//Error예정.(col2 가 not null 인데 안 넣었기 때문에) void save(); }
>> TDAO.java (ITDAO.java 도 알아서 만들기)
@Repository("ITDAO01") public class TDAO implements ITDAO { @Autowired IT1Mapper t1Mapper; @Autowired IT2Mapper t2Mapper; @Override @Transactional public void save() { t1Mapper.save(); t2Mapper.save();//Error예정 } }
>> TestController.java
@Controller public class TestController { @Autowired @Qualifier("ITDAO01") ITDAO TDAO; @RequestMapping("do2") public void process2() { TDAO.save(); } }
do2 를 요청명으로 실행시 db에 관한 에러로 500페이지가 뜨며, t1 에 저장되었다가 t2 에서 에러가 나면서 t1 의 저장도 같이 취소된다. 2) @Transcational 미사용시
@Repository("ITDAO01") public class TDAO implements ITDAO { @Autowired IT1Mapper t1Mapper; @Autowired IT2Mapper t2Mapper; @Override // @Transactional public void save() { t1Mapper.save(); t2Mapper.save();//Error예정 } }
do2 를 요청명으로 실행시 db에 관한 에러로 500페이지가 뜨며, t1 에 저장되고 t2 에서 에러나면 t1 의 저장은 그대로 t2는 취소된다. 2-1) @Transcational 미사용시 : try-catch문으로 @Transcational 과 같은 결과 내기
@Controller public class TestController { @Autowired @Qualifier("ITDAO01") ITDAO TDAO; @RequestMapping("do2") public void process2() { try { TDAO.save(); }catch(Exception e) { System.out.println("process2 정상처리 실패"); e.printStackTrace(); } } }
do2 를 요청명으로 실행시 뷰가 없다는 404페이지는 뜨나, 결과는 @Transactional 을 사용했을 때와 같이 t1, t2 모두 취소된다.