본문 바로가기
코딩/수업 정리

21.02.09 [055] Tue

by 6^6 2021. 2. 8.
728x90

스프링
트랜잭션
interceptor
aop
스프링시큐리티

스크링 부트(유지보수 쪽으로 가려면)
부트스트랩

 

트랜잭션

★★상당히 중요 실무에서 무조건 사용

사용방법은 쉬움

 

트랙잭션이란?

트랜잭션은 DB와 연관되어있다.(프로그램과 연관되어있는것이 아니다)

DB에는 commit(영속적인 저장)과 rollback(되돌리기)기능이 있다.

은행ATM, 카드결제작업과 마일리지 적립작업은 트랜잭션으로 작동해야 한다.

ex) 댓글을 두단계로(reply shape, reply view)로 작성한다. 근데 소프트웨어 또는 db쪽에서 등등 문제가있어 첫번째단계에선 적용이됐는데 두번째단계에서 오류가 났을때 롤백없으면 망함.  

 

어떤 일련의 작업의 의미임(한번에 이루어져야 하는 작업 단위)

모두 에러없이 끝나야하면, 만약 중간에 에러가 발생한다면, 에러 발생 이전 시점까지 작업되었던 내용은 모두 원상복구 되어야함.

500또는 404등의 에러처리가 아니면, 에러 발생시DB로 하여금 원상복구하도록 DB에 요청하는 것임

 

가장간단하게 @Transactional 에노테이션으로 구현해야함

 

↓Transaction 구현 프로젝트 파일 더보기

더보기
[TransactionController.java]
package edu.bit.board.controller;

import java.sql.SQLException;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import edu.bit.board.page.Criteria;
import edu.bit.board.page.PageVO;
import edu.bit.board.service.BoardService;
import edu.bit.board.service.TransactionService;
import edu.bit.board.vo.BoardVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@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();
		} else if (num == 4) {
			log.info("transionTest4");
			tranService.transionTest4();
		} else if (num == 5) {
			log.info("transionTest5");
			tranService.transionTest5();
		} else if (num == 6) {
			log.info("transionTest6");
			tranService.transionTest6();
		} else if (num == 7) {
			log.info("transionTest7");
			tranService.transionTest7();
		}

	}

}
[TransactionService.java]
package edu.bit.board.service;

import java.sql.SQLException;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.bit.board.mapper.BoardMapper;
import edu.bit.board.vo.BoardVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@Service
@AllArgsConstructor
public class TransactionService {

	private BoardMapper mapper;
	// 전처럼 위에 @안써도 자동으로 객체 생성해서 들어감

	@Transactional
	public void transionTest1() {

		log.info("transionTest1()테스트 ");
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션1");
		boardVO.setbName("트랜잭션1");
		boardVO.setbTitle("트랜잭션1");

		mapper.insertBoard(boardVO);

		boardVO.setbContent("트랜잭션2");
		boardVO.setbName("트랜잭션2");
		boardVO.setbTitle("트랜잭션2");

		mapper.insertBoard(boardVO);
	}

	public void transionTest2() {

		log.info("transionTest2()테스트 ");
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션1");
		boardVO.setbName("트랜잭션1");
		boardVO.setbTitle("트랜잭션1");

		mapper.insertBoard(boardVO);

		boardVO.setbContent("트랜잭션2");
		boardVO.setbName("트랜잭션2");
		boardVO.setbTitle("트랜잭션2");

		// 일부러 트랜잭션을 위한 것
		boardVO = null;
		mapper.insertBoard(boardVO);
	}

	@Transactional 
	//이걸 쓰면 트랜잭션2는 안들어감. 이 어노테이션은 DB관련된것. 
	//이 안에서 에러가 나게되면 해당DB는 rollback시킨다. 그래서 이부분은 안들어가게된다.
	public void transionTest3() {

		log.info("transionTest3()테스트 ");
		BoardVO boardVO = new BoardVO();

		boardVO.setbContent("트랜잭션1");
		boardVO.setbName("트랜잭션1");
		boardVO.setbTitle("트랜잭션1");

		mapper.insertBoard(boardVO);

		boardVO.setbContent("트랜잭션2");
		boardVO.setbName("트랜잭션2");
		boardVO.setbTitle("트랜잭션2");

		// 일부러 에러를 내게 함 //트랜잭션을 위한 것
		boardVO = null;
		mapper.insertBoard(boardVO);
	}

	// uncheckedExeption(롤백 함) - try catch 안묶어 줘도 되는것
	@Transactional
	public void transionTest4() {
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션4");
		boardVO.setbName("트랜잭션4");
		boardVO.setbTitle("트랜잭션4");

		mapper.insertBoard(boardVO);

		//RuntimeException(uncheckedExeption)오류를 일부러 넣음
		throw new RuntimeException("RuntimeException for rollback");
	}

	// CheckedExeption 테스트(롤백 안함) - try catch 묶어줘야하는것=개발자가 맡김
	//4번과 차이 반드시 알기 checked, unchecked.
	@Transactional
	public void transionTest5() throws SQLException {
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션5");
		boardVO.setbName("트랜잭션5");
		boardVO.setbTitle("트랜잭션5");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");
	}

	// @Transactional의 rollbackFor 옵션을 이용하면 Rollback이 되는 클래스를 지정가능함.
	// Exception예외로 롤백을 하려면 다음과 같이 지정하면됩니다. @Transactional(rollbackFor =
	// Exception.class)
	// 여러개의 예외를 지정할 수도 있습니다. @Transactional(rollbackFro = {RuntimeException.class,
	// Exception.class})
	//언첵이든 첵이든 
	@Transactional(rollbackFor = Exception.class)//throws만해도 X. = Exception.class이거 달아줘야함.
	public void transionTest6() throws SQLException {
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션6");
		boardVO.setbName("트랜잭션6");
		boardVO.setbTitle("트랜잭션6");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");
	}

	@Transactional(rollbackFor = SQLException.class)
	public void transionTest7() throws SQLException {
		BoardVO boardVO = new BoardVO();
		boardVO.setbContent("트랜잭션7");
		boardVO.setbName("트랜잭션7");
		boardVO.setbTitle("트랜잭션7");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");
	}

}
[BoardMapper.java]
package edu.bit.board.mapper;

import edu.bit.board.vo.BoardVO;

public interface BoardMapper {

	//트랜잭션
	public void insertBoard(BoardVO boardVO);
}
[BoardMapper.xml]
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="edu.bit.board.mapper.BoardMapper">
	<!-- ↑인터페이스 -->

	<!-- 트랜잭션 -->	
	<insert id="insertBoard" >
	<![CDATA[
		insert into mvc_board (bId, bName, bTitle, bContent, bHit, bGroup, bStep, bIndent) values (mvc_board_seq.nextval, #{bName}, #{bTitle}, #{bContent}, 0, mvc_board_seq.currval, 0, 0)
	]]>
	</insert>

</mapper>

 

 

 

 

 

마지막으로 진짜 트랜젝션을 사용할 수 있게 만드는것.

[root-context.xml]- 이 부분이 들어가줘야 @Transactional을 사용할 수 있다.
 		...
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
       								//↑커넥션풀객체
   </bean>
 <tx:annotation-driven transaction-manager="transactionManager" />
//↑ @Transactional 애노테이션이 들어갈 수 있게 하는것
		...

 

num==1만 일단 구현

 

 

 

5번방법!!

checked에서는 tran붙여도 반영안됨

개발자가 trycatch를 사용해서 throws를 직접적으로 하기때문에 (개발자가 직접 수정할거라고하기때문에)transzctional이 반영이 안됨. 그래도 반영이 되기때문에 chechedexception을 해주는게 좋다.

 

기본게시판에선 @Transactional 달아줄곳이  serviceImpl에서 댓글밖에없다. 그리고 절!대! 절대로 controller에 @Transactional이 들어가서는 안된다.

왜?? 일단 컨트롤러에선 트랜젝션이 잘 안먹는다.

컨트롤러는 기본적으로 하는 역할이 그냥 view정도만 결정을 해주는 곳이기 때문에..

그래서 @Transactional은 내가 구현해야할 로직이 있는곳이 service단에 무조건 넣어줘야한다!!!(그냥 @Override위에 붙여 넣는다.) 

그리고 select는 @Transactional이 대상이 아니고, 왜 댓글에만 저걸 넣느냐면 댓글에 updateShape과 insertReply 두개가 다 들어가기 때문이다. 두개이상이 들어가는 거면 @Transactional이 들어갈 대상이다.

 

 

 

 

주의할건 checked unchecked 에 따른 구현 상태이고 트랜젝션은 service단에서 구현해야한다. 이것만이라도 기억할것!!!

 

 

 

========================================================================================================================================================

메소드 delete를 줘야함?

어제 ajax delete하는것 소스코드 정답

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>REST Delete</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script   src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
      $(".a-del").click(function(event) { 
         event.preventDefault();
         console.log("a-del click");
         //data
         var trObj = $(this).parent().parent();//자바스크립트 클로저

         $.ajax({
            type : 'DELETE', //method
            url : $(this).attr("href"), //주소를 받아오는 것이 포인트.
            cache : false,
            success : function(result) {
               console.log("result: " + result);
               if (result == "SUCCESS") {
                  $(trObj).remove();
               }
            },
            errer : function(e) {
               console.log(e);
            }
         }); //end of ajax
      }); 
   });
</script>

</head>
<body>
   <table width="500" cellpadding="0" cellspacing="0" border="1">
      <tr>
         <td>번호</td>
         <td>이름</td>
         <td>제목</td>
         <td>날짜</td>
         <td>히트</td>
         <td>삭제</td>
      </tr>
      <c:forEach items="${list}" var="vo">
         <tr>
            <td>${vo.bId}</td>
            <td>${vo.bName}</td>
            <td><c:forEach begin="1" end="${vo.bIndent}">[re]</c:forEach> <a
               id="a-content"
               href="${pageContext.request.contextPath}/restful/board/${vo.bId}">${vo.bTitle}</a></td>
            <td>${vo.bDate}</td>
            <td>${vo.bHit}</td>
            <td><a class="a-del" data-bid='${vo.bId}' href="${pageContext.request.contextPath}/restful/board/${vo.bId}">삭제</a></td>
         </tr>
      </c:forEach>
      <tr>
         <td colspan="5"><a href="write_view">글작성</a></td>
      </tr>
   </table>
</body>
</html>
package edu.bit.board.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import edu.bit.board.service.BoardService;
import edu.bit.board.vo.BoardVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@AllArgsConstructor
@RestController // 스프링 4.0부터 지원
@RequestMapping("/restful/*")
public class RestBoardController {

	// 5버전으로 오면서 @Autowired 를 안넣어줘도 알아서 객체생성됨
	private BoardService boardService;

	// 1. list(처음 진입화면이므로 화면이 깜박여도 상관없으므로 @Controller방식으로 접근 - 이땐 list를 리턴)
	@GetMapping("/board")
	public ModelAndView list(ModelAndView mav) {
		mav.setViewName("rest_list");//어떤 jsp를 불러올지
		mav.addObject("list", boardService.getList());
		log.info("getList");
		return mav;// 이제 return값이 view가 아니라
	}

	@GetMapping("/board/{bId}")
	// public String rest_content)view(@PathVriable("bId) String bId, Model model)
	// 이렇게 path variable로 처리해도 되지만 command객체가 있기때문에 걍 밑에있는 코드처럼 처리한다.
	public String rest_content_view(BoardVO boardVO, Model model) {
		log.info("rest_content_view");
		model.addAttribute("content_view", boardService.getBoard(boardVO.getbId()));
		log.info("content_view");
		return "content_view";
	}

	@DeleteMapping("/board/{bId}")
	public ResponseEntity<String> rest_delete(BoardVO boardVO, Model model) {
		// ResponseEntity는 restful을 위해 제공되는 대표적인 것 중 하나이다.
		ResponseEntity<String> entity = null;
		log.info("rest_delete..");
		try {
			boardService.remove(boardVO.getbId());
			// 삭제가 성공하면 성공 상태메시지 저장
			entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
		} catch (Exception e) {
			e.printStackTrace();
			// 댓글 삭제가 실패하면 실패 상태메시지 저장
			entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
		}
		
		log.info("delete");
		// 삭제 처리 HTTP 상태 메시지 리턴
		return entity;

	}
}

parent.parent이부분은 선택자임.

 

id와 class의 차이

id는 한 문서에서 한 번만 사용이 가능하다.(유일무이)

class는 한 문서에서 여러번 사용이 가능하다.

따라서 여기서 class로만 사용가능하고  id로 사용하면 오류가 난다.

 

========================================================================================================================================================

DB Modeling

 

 

exerd파일 실행

 

새테이블 편집하고 스페이스바

논리, 물리

논리이름:지금 sts에 보이는 이름

물리이름:오라클에 들어가는 이름 - 무조건 소문자로 들어가야한다!

 

유일키는 언제나 'id'로 명명

소문자 사용

 

 

↑외래키(foreign-key)는 앞에 테이블 명을 적어준다.

 

 

NN은 not null

 

 

 

 

 

주문은 두개의 외래키를 갖는다 따로 pk를 지정해주지 않으면 이 두개가 주키(pk)가 된다. n:n관계는 있을 수 없으므로 주문번호를 만들어 pk로 준다음 1:n관계로 바꾸어준다.

 

 

 

 

빨간점선=비식별 - 게시판의 회원키가 pk로 들어가지 안아도 될때

초록실선=식별 - 외래키가 게시판의 주 키(pk)가 들어가야할때

 

이제 오라클 만들기

 

 

 

board와 member생성됨

 

 

 

 

========================================================================================================================================================

오늘의 문제

1.아래에 대하여 설명하시오.
-트랜잭션 이란?
-rollback 과 commit 이란?
2.스프링에서의 트랜잭션 처리 방법은?

728x90

'코딩 > 수업 정리' 카테고리의 다른 글

21.02.15 [057] Mon  (0) 2021.02.15
21.02.10 [056] Wed  (0) 2021.02.10
21.02.08 [054] Mon  (0) 2021.02.08
21.02.05 [053] Fri  (0) 2021.02.05
21.02.04 [052] Thu  (0) 2021.02.04

댓글