본문 바로가기

bitcamp/면접족보

면접족보 21/02/09_트랜잭션

1. 아래에 대하여 설명하시오.

※트랜잭션이란? (DB rollback처리)
· 데이터베이스의 상태를 변환시키기 위한 작업의 단위(여러과정들이 합쳐진 상태)를 말하며,

  하나의 트랜잭션은 Commit 혹은 Rollback 된다.

· 트랜잭션을 사용하기 위해 root-context.xml에 다음과 같이 작성하도록 한다.

 

 

 

 

※Rollback과 Commit이란?

· Commit은 모든 작업을 정상적으로 적용시켜 실행한다는 명령어로,
  트랜잭션에 대한 작업이 성공적으로 완료되었을 때 Commit 연산이 수행되어 처리과정이 모두 반영된다.
· Rollback은 문제가 발생했을 때, 처리과정에서 발생한 변경 사항을 취소시키는 명령어로,
  작업 도중 오류가 발생한다면 작업되었던 부분에서 오류 발생 이전 시점까지 모두 복구하기 위해서 Rollback이 수행된다.
  (즉, 트랜잭션에 대한 작업이 비정상적으로 처리되었을 때 Rollback 수행, Commit한 시점까지만 복구)
  Rollback은 오류 페이지에 대한 처리가 아니며, 오류 발생시 원상복구하도록 DB에 요청한다.

 

 

2. 스프링에서의 트랜잭션 처리 방법은?

· Controller은 view 정도를 결정하는 곳이므로 아래와 같이 로직을 처리하는 Service에서 @Transactional를 사용하도록 한다.

· uncheckedExeption과 checkedExeption에 따라 Rollback의 차이가 있으므로 @Transactional 사용 시에 조심할 것!

 

<TransactionService.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 @Log4j
 @AllArgsConstructor
 @Service
 public class TransactionService {
    private BoardMapper mapper;
    
    //1번: DB에 내용이 입력되지 않음 (uncheckedExeption: 롤백함)
    //RuntimeException은 unchecked로 개발자가 예외처리를 명시하지 않아도 되기 때문에, 오류가 발생하였으므로 트랜잭션이 처리해줌
    @Transactional 
    public void transionTest1() {
        BoardVO boardVO = new BoardVO();
        boardVO.setbContent("트랜잭션1");
        boardVO.setbName("트랜잭션1");
 
        mapper.write(boardVO);
        
        //강제로 예외를 발생시킴, 이 부분이 없다면 내용이 DB에 입력될 것!
        throw new RuntimeException("RuntimeException for rollback");
    }
   
    //2번: DB에 내용이 입력됨(checkedExeption: 롤백안함)    
    //checked는 개발자가 직접 예외 처리를 해야 하기 때문에 직접적으로 개발자가 수정할 것이라고 판단하여 롤백을 시키지 않음
    //checked는 롤백을 하지 않기 때문에 내용에 대한 try-catch 처리 없으면 위험!!(현업에서 꼭 주석으로 명시해주기!)
    @Transactional
    public void transionTest2() throws SQLException{
        BoardVO boardVO = new BoardVO();
        boardVO.setbContent("트랜잭션2");
        boardVO.setbName("트랜잭션2");
 
        mapper.write(boardVO);
 
        //강제로 예외를 발생시킴, 
        throw new SQLException("SQLException for rollback");
    }
 
    //3번: 모든 예외 클래스에 대해서는 롤백시켜라! 그래서 DB에 내용이 들어가지 않음
    //@Transactional의 rollbackFor 옵션을 이용하면 Rollback이 되는 클래스 지정가능.
    // 여러개의 예외를 지정 가능 (rollbackFro = {RuntimeException.class, Exception.class})
    @Transactional(rollbackFor = Exception.class)
    public void transionTest3() throws SQLException{
        BoardVO boardVO = new BoardVO();
        boardVO.setbContent("트랜잭션3");
        boardVO.setbName("트랜잭션3");
 
        mapper.write(boardVO);
        
        throw new SQLException("SQLException for rollback");
    }
 }
cs

 

<TransactionController.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 @Log4j
 @AllArgsConstructor
 @Controller
 public class TransactionController {
    private TransactionService tranService;
    
    @GetMapping("/tran/{num}")
    public void transiotn(@PathVariable("num"int num) throws SQLException { 
         if(num == 1){
            log.info("transionTest1");
            tranService.transionTest1();
         }else if(num == 2) {
             log.info("transionTest2");
             tranService.transionTest2();
         }else if(num == 3) {
             log.info("transionTest3");
             tranService.transionTest3();
         }
    }
 }
cs

 

 

※연습문제

RESTful과 ajax를 사용하여 게시글 수정하시오(PUTMapping 사용 할 것!)

 

<RestBoardController.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 @Log4j 
 @AllArgsConstructor
 @RestController
 @RequestMapping("/restful/*")
 public class RestBoardController {
    private BoardService boardService;
 
    @GetMapping("/board/{bId}")
    public ModelAndView rest_content_view(BoardVO boardVO, ModelAndView mav) {
        log.info("rest_content_view");
        
        mav.setViewName("rest_content_view");
        mav.addObject("content_view", boardService.content(boardVO.getbId()));
        return mav;
    }
    @PutMapping("/board/{bId}")
    public ResponseEntity<String> rest_modify(@RequestBody BoardVO boardVO, ModelAndView mav) {
        ResponseEntity<String> entity = null;
        log.info("rest_update");
        try {
            boardService.modify(boardVO);
            entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
        }
        return entity;
    }
 }
cs

 

 

<rest_content_view.jsp>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
 <script type="text/javascript">
    $(document).ready(function(){
        $("#form").submit(function(event){
            event.preventDefault(); 
 
            var bId = $("#bId").val();
            var bName = $("#bName").val();
            var bTitle = $("#bTitle").val();
            var bContent = $("#bContent").val();
                
            var form = { 
                bId: bId,
                bName: bName,
                bTitle: bTitle,
                bContent: bContent
            } //json 사용
            
            $.ajax({
                type : "PUT",
                url: $("#form").attr("action"),           
                contentType: 'application/json; charset=utf-8',  
                //json을 사용할 때는 보안상의 문제로 표기 필수!
                //controller에서는 @RequestBody를 이용해 json 데이터 송수신.
                data: JSON.stringify(form),
               //obj의 data를 문자열화 시켜줌, 그렇지 않으면 k:v 패턴을 인식하지 못함.
                success: function (result) {                           
                    if(restult == "SUCCESS"){
                         console.log(result);
                         $(location).attr('href''$({pageContext.request.contextPath}/restful/board)')    
                         //window.location.href = "$({pageContext.request.contextPath}/restful/board" , dom 객체 location 사용!          
                    }
     },
             error: function (e) {
                  console.log(e);
             }
         });
    });
 });                
 </script>
 </head>
 <body>
 <form id="form" action="${pageContext.request.contextPath}/restful/board/${content_view.bId}" method="post">
    <input type="hidden" name="bId" value="${content_view.bId}">
    <table width="500" cellpadding="0" cellspacing="0" border="1">
        <tr>
            <td>번호</td>
            <td><input type="text" id="bId" value="${content_view.bId}"></td>
        </tr>
        <tr>
            <td>히트</td>
            <td><input type="text" id="bHit" value="${content_view.bHit}"></td>
        </tr>
        <tr>
            <td>이름</td>
            <td><input type="text" id="bName" value="${content_view.bName}"></td>
        </tr>
        <tr>
            <td>제목</td>
            <td><input type="text" id="bTitle" value="${content_view.bTitle}"></td>
        </tr>
        <tr>
            <td>내용</td>
            <td><textarea rows="10" id="bContent">${content_view.bContent}</textarea></td>
        </tr>        
        <tr>
            <td colspan="5"><input type="submit" value="수정"> 
            &nbsp;&nbsp; <a href="${pageContext.request.contextPath}/restful/board">목록보기</a>
            &nbsp;&nbsp; <a href="${pageContext.request.contextPath}/restful/board/reply_view/${content_view.bId}">답변</a>
            </td>
        </tr>
    </table>
    </form>
 </body>
cs
 

 

 

<구현 화면>

 : form 태그의 method = "post"는 ajax 전송과는 무관!

 

 

 

 

 

 

 

'bitcamp > 면접족보' 카테고리의 다른 글

면접족보 21/02/15_ AOP  (0) 2021.02.17
면접족보 21/02/10_RESTful, Intercptor  (0) 2021.02.17
면접족보 21/02/08_RESTful  (0) 2021.02.16
면접족보 21/02/05_비동기ajax  (0) 2021.02.15
면접족보 21/02/04_MyBatis  (0) 2021.02.15