IT/development

[mybatis] mybatis 이중 foreach insert(feat. 이중 계층 객체 저장)

알 수 없는 사용자 2022. 11. 21.


mybatis를 이용해서 계층 구조의 DTO 혹은 VO객체를 저장하는 방법을 기록한다.
대상 DBMS: mysql, mariaDB
아래처럼 객체가 객체를 참조하는 경우 이를 저장하는 방법이다.(시간 상 코드 위주로 최대한 심플하게 정리)

마블 캐릭터 데이터를 조회하는 오픈 API가 있다고 가정하고 API 결과를 list에 담아
루프를 돌려 객체에 세팅한 뒤 DB에 저장하는 로직 예시(상상 코딩 😅)

// 메인객체
@Getter
@Setter
public class TestVO {

    private Long mem_no;
    private String data_type;                                   
    private String code;                                        
    private List<addDataVO> addList = new ArrayList<>();     
}
// 서브 객체
@Getter
@Setter
public class addDataVO {
    private String list_data;                      
    private String list_data_description;           
    
    // 필드 데이터 설정하기 위한 생성자
    public AddDataInfoVO(String additional_data, String additional_data_description) {
        this.additional_data = additional_data;
        this.additional_data_description = additional_data_description;
    }
}

데이터 구조 예시

{
    "mem_no": "1",
    "data_type": "member",
    "code": "0090",
    "addList": [
    {
        "list_date": "아이언맨",
        "list_data_description": "마블 개국공신"
        }
    ]
}

service

// 샘플 코드
public void insertTest(Long mem_no, String apiKey) throws Exception {
		// 등록용 list	
		List<TestVO> insertList = new ArrayList<>(); 
		List list = null;
        Gson gson = new Gson();
        String json = "";

		//외부 api에서 값을 가져와 list에 담고 루프를 돌려서 아래처럼 객체를 생성해 세팅한다는 가정(JSON 타입의 데이터가 list에 담겨져 있음)
		list = apiRequest.Apilist(apiKey);

		// (org.springframework.util.CollectionUtils.isEmpty 이용)list가 null이 아니거나 빈값이 아닐 경우 루프 돌면서 객체 생성 해 api 데이터 세팅	
        if (!CollectionUtils.isEmpty(list)) {
        	// gson 이용해 JSON타입의 스트링으로 변환해서 담음
            json = gson.toJson(list);
            // JSONArray에 담고 루프
            JSONArray ListArr = new JSONArray(json);
            for (Object obj: ListArr) {
                JSONObject jsonObj = (JSONObject) obj;
                TestVO vo = new TestVO();
                vo.setMem_no(mem_no);
                vo.setData_type("member");
                vo.setCode(String.valueOf(jsonObj.getInt("code")));
                // 서브 객체의 생성자 이용해서 값 세팅
                vo.getAddList().add(new addDataVO(jsonObj.getString("hero"), "테스트"));
                insertList.add(vo);
               	}
	} else {	// list가 null이거나 빈값인 경우 예외처리(예외는 Controller의 catach문에서 받아서 처리)
    			throw new Exception();
	// list 저장 호출
	insertDataList(insertList);
}

// 위에서 호출한 메소드 예시
public void insertDataList(List<TestVO> TestVOList) throws Exception {
// 데이터 db 저장
testMapper.insertTest(TestVOList);
    }

mapper(interface)

public void insertTest(List<TestVO> TestVOList);

mapper(xml)

<!-- 사실상 제일 중요한 부분임--> 
<insert id="insertTest" parameterType="TestVO">
        INSERT INTO test
        (
            mem_no,
            data_type,
            code,
            list_data,
            list_data_description,
            create_date
        )
        VALUES
        <!-- 바깥쪽 포문 collection에는 mybatis에 paramter로 던진게 list니까 list를 기입, 별칭은 "item"으로 설정--> 
        <foreach collection="list" item="item" separator=",">
        	<!-- 안 쪽 포문 collection에는 서브 객체의 list 변수명을 기입, 별칭은 "it"로 설정 --> 
            <foreach collection="item.addList" item="it" separator=","> 
                (	
                	<!-- 바깥쪽 포문은 item.으로 접근 --> 
                    #{item.mem_no},	
                    #{item.data_type},
                    #{item.code},
                    <!-- 서브 객체의 필드명 기입
                    (안 쪽 포문 별칭은 위에서 it로 설정했기에 it.로 접근하면 됨)  
                    --> 
                    #{it.list_data},	
                    #{it.list_data_description}, 
                    now()
                )
            </foreach>
        </foreach>
    </insert>

정상 실행 시 아래처럼 DB에 쿼리를 보낸다.(예시 데이터라서 마블 데이터로 적었음)

INSERT INTO test
        (
            mem_no,
            data_type,
            code,
            list_data,
            list_data_description,
            create_date
        )
        VALUES

                (
                    1,
                    'member',
                    '0090',
                    '아이언맨',
                    '마블 개국공신',
                    now()
                )
             , 
                (
                    2,
                    'member',
                    '0091',
                    '토르',
                    '천둥의 신',
                    now()
                )
             , 
                (
                    3,
                    'member',
                    '0092',
                    '닥터 스트레인지',
                    '소서러 슈프림',
                    now()
                )

개인 스터디 기록을 메모하는 공간이라 틀린점이 있을 수 있습니다.

틀린 점 있을 경우 댓글 부탁드립니다.

 

[mybatis] foreach parameterType hashmap 예제

미래의 나를 위해 기록한다. 😃mybatis에서 foreach를 돌릴 때 list는 이제 좀 익숙해 졌는데 map은 아직 좀 서툰 느낌이 들어 기록한다.예제는 동적으로 insert문의 내용과 SELECT문의 내용을 채우는 예

yaga.tistory.com

 

[mybatis] mybatis 동적쿼리(feat. <where></where>)

목차 mybatis Dynamic SQL 😃 계속 실수 했던 동적쿼리이다. 오늘 나는 이걸 이해 했지만 미래의 넌 또 까먹을 수 있으니 여기에 메모해 둔다. 동적 WHERE 회원 테이블에서 회원이름과 이메일의 존재에

yaga.tistory.com

댓글