[DB]Mybatis 활용 Mysql 반복 insert하기

Inung_92·2023년 1월 21일
1

DB

목록 보기
1/3
post-thumbnail

기본적인 insert

이전에 Mybatis를 활용하여 레코드를 등록하는 방법을 알아보았다. 다시 한번 간단하게 복습을 하고 반복적인 insert에 대해서 알아보자. 코드의 순서는 Mapper.xml에서부터 jsp까지로 작성해보겠다.(DB에서 시작해서 서버페이지까지 도달)

혹시 이전 게시글을 보지않았다면 📖여기를 참고하자.

상품 등록

Product(상품) 테이블에 상품을 1건 등록하는 상황을 가정하여 코드를 작성해보자.

⚡️Mybatis Mapper.xml

<!--insert 시작-->
<insert id="insert" parameterType="Product">
  	<!--parameterType은 해당 DTO명-->
	insert into 테이블명(product_id, name...생략)
  	values(#{product_id}, #{name}...생략)
</insert>

⚡️ProductDAO.java

public void ProductDAO{
	//DAO를 호출하는 서비스로부터 세션 획득을 위해 선언
	Sqlsession sqlSession;
    
    //SqlSession 획득 메서드
    public void setSqlSession(SqlSession sqlSession){
    	this.sqlSession = sqlSession;
    }
    
	//insert 메서드
    public void insert(Product product) throws ProductException{
	    //파라미터로 DTO 전달
    	int result = 0;
        result = sqlSession.insert("insert", product);
        if(result < 1){
        	//insert 실패 시 해당 영역에서 수행결과를 예외 전달로 전송
        	//예외 처리를 통해 전달할 실행문 작성
        }
    }
}

⚡️Product.java(DTO)

public class Product{
	//컬럼명과 동일한 멤버변수 선언
	private int product_id;
    private String name;
    private String brand;
    .....생략
    
    //Getter/Setter 생략
}

여기까지 코드를 작성하면 DB로부터 쿼리문을 수행할 준비가 끝난 상태이다. 이제 서버페이지에서 상품 등록에 대한 코드를 작성해보자.

⚡️등록.jsp

<%@ 지시부 생략%>
<%! //선언부(멤버영역)
	//싱글톤이 적용된 Mybatis 객체 멤버로 보유
	MybatisConfig mybatisConfig = MybatisConfig.getInstance();
    
    //쿼리문을 수행할 DAO 보유
    ProductDAO productDAO = new ProductDAO();
%>

<% //스크립틀릿 영역(Servlet의 services() 메서드)
	request.setCharset("utf-8"); //인코딩 설정
    
    //등록할 empty DTO생성
    Product product = new Product();
    product.setName(request.getParameter("name"));
    ....생략
    
    //insert문 실행
    try{
    productDAO.insert(product);
    } catch(ProdcutException e){
    	...예외발생 시 처리할 실행문 입력
    } finally{
    	//Sql세션 반납
    	mybatisConfig.release(sqlSession);
    }
%>

이렇게해서 DB에 하나의 상품을 등록하는 코드를 역순으로 작성해보았다. Mybatis를 활용하여 1건의 insert는 위와 같이 이루어진다. 그렇다면 여기서 만약 상품 1건에 색상, 사이즈 등의 복수 형태의 레코드를 동시에 등록을 해야한다면 어떻게 해야할까?

이런 상황을 대비해서 반복 insert하는 방법을 알아보자.


반복적인 insert

foreach문

인자 값으로 전달받은 collection을 바탕으로 반복적인 쿼리문을 수행할 때 사용

속성

  • collection : 전달받은 인자를 속성값으로 삽입(map, list 등)
  • item : collection에서 전달받은 인자값을 호출할 이름을 부여
  • open : 구문이 시작될 때 삽입할 문자열을 지정
  • close : 구문이 종료될 때 삽일할 문자열을 지정
  • separator : 반복되는 구문 사이에 삽입할 문자열을 삽입
  • index : 인덱스 값을 0부터 반환하는 속성

속성을 xml로 작성하면 아래와 같다.

<foreach collection="list"
         separator=","
         item="item"
         open="("
         close=")"
         index="index">
</foreach>

예제

위에서 등록한 Product의 PK를 FK로 참조하는 복수의 Color를 삽입해보겠다. 전체 코드를 작성하면 너무 길어지니 반복되는 코드들은 생략하며 작성하겠다.

이번엔 DB에서부터가 아닌 JSP에서부터 시작해보자.

⚡️반복등록.jsp(별도로 jsp를 작성하는것이 아니라 위의 jsp를 연속하여 작성하는 개념)

<%@ 지시부 생략%>
<%! //선언부(멤버영역)
	//싱글톤이 적용된 Mybatis 객체 멤버로 보유
	MybatisConfig mybatisConfig = MybatisConfig.getInstance();
    
    //쿼리문을 수행할 DAO 보유
    ProductDAO productDAO = new ProductDAO();
    ColorDAO colorDAO = new ColorDAO();
    
    //반복 insert의 인자로 사용할 List
    List<Color> colorList = new ArrayList();
%>

<% //스크립틀릿 영역(Servlet의 services() 메서드)
	request.setCharset("utf-8"); //인코딩 설정
    
    //등록할 empty DTO생성
    Product product = new Product();
    product.setName(request.getParameter("name"));
    ....생략
    
    for(int i = 0; i < '넘어온 요청수만큼'; i++){
      Color color = new Color();
      //Product 객체 자체를 보유하여 필요시 멤버 추출
      color.setProduct(product);
      color.setColor_name(request.getParameter("color_name");
      ....생략

      //반복문 내에서 List에 추가
      colorList.add(color);
    }
//insert문 실행
  try{
      productDAO.insert(product);

      //상품 1건이 등록 후 Color객체가 들어있는 list를 이용하여 insert 호출
      colorDAO.insert(colorList); //인자로 List 전달
  } catch(ProdcutException e){
      ...예외발생 시 처리할 실행문 입력
  } catch(ColorException e){
      ...예외발생 시 처리할 실행문 입력
  } finally{
      //Sql세션 반납
      mybatisConfig.release(sqlSession);
  }
%>

여기서 중요한 부분은 분명히 List를 인자로 넘겨준다. 그렇다면 DAO에서 List.size()만큼 반복문을 수행하여 insert를 하는 것일까? 한번 DAO를 들여다 보자.

⚡️ColorDAO.java

public class ColorDAO {
	//Sql세션 선언
	private SqlSession session;
	
    //Sql세션 획득 메서드
	public void setSession(SqlSession session) {
		this.session = session;
	}
	
    //insert 메서드
	public void insert(List<Color> list) throws ColorException{
	    //반환값이 아닌 예외발생 지표로 사용할 변수
		int result = 0;
        //insert 호출(list 인자로 전달)
		result = session.insert("Color.insert", list);
        //실패 시 예외 전달
		if(result < 1) {
			throw new ColorException("색상 등록실패");
		}
	}
}

DAO에서도 반복문을 수행하지 않는다. 그러면 오늘의 궁금증을 해결해줄 foreach문을 만나러 Mapper.xml으로 이동해보자.

⚡️ColorMapeer.xml

<mapper namespace="Color">
	<insert id="insert" parameterType="java.util.List">
      	<!-- 변동사항이 없는 고정된 쿼리문 -->
		insert into color(product_idx, color_name)
		values <!-- 이후부터 변동사항이 발생 -->
      
        <!--
		collection : 전달받을 인자의 자료형은 List
		separator : ','을 기준으로 list내의 item 구분
		item : list안의 객체를 지명할 이름명 
		-->
		<foreach collection="list" separator="," item="item">
			(#{item.product.product_idx}, #{item.color_name})
          	<!--
			여기서 item은 Color객체를 의미함. List에 들어있는 1건의 Color.
			그렇다면 item. 뒤에는 해당 멤버변수명이 들어오면된다는 말임.
 			-->
		</foreach>
      
	</insert>
</mapper>

쿼리 구문에서 foreach를 통해 자동으로 반복을 수행하면서 매핑을 해준다. 이전에는 직접 쿼리문에 values(record1), (record2).... 이런식으로 작성을 했다면 foreach를 사용할 경우 한번의 쿼리문 작성으로 반복을 자동으로 해주니 얼마나 편한지 모르겠다.


마무리

느낀점

  • 각 DAO별로 Connetcion을 하지않고, DAO를 사용하는 서비스에서 세션을 주입하여 사용하기 때문에 코드의 반복이 줄어들고 트랜잭션을 공유하니 안전한 DML수행이 가능
  • 쿼리문과 수행로직이 구분되어있어 코드 가독성이 좋아지고 유지보수 간 간편함

Java SE의 문법을 배우면서 하드코딩 위주로 기초부터 개념을 잡아가다가 점점 여러 라이브러리와 프레임워크를 접하게되면서 코드는 간결해지지만 수행되는 원리를 이해하는 것이 어려워지고 있다는 것을 느낀다.
그래도 코드가 점점 정리가되어가는 느낌이 들고 오류가 발생한 경우 해당 위치를 찾아서 수정하는 것이 한결 간편해졌다. 이전에는 하나의 .java에 모든 것이 들어있었다면 이제는 각 기능 또는 역할별로 구분해서 사용을하다보니 위에서 느낀것처럼 좋은 부분들이 많다. 다만 아직 기본문법 사용에 지나지 않으니 더 활용을하고 응용을 해봐야 할 듯하다.

profile
서핑하는 개발자🏄🏽

0개의 댓글