ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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 모두 취소된다.

     

    댓글

Designed by Tistory.