IT/development

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

알 수 없는 사용자 2022. 11. 21. 06:56
반응형

목차


    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()
                    )

     

    반응형