Loading...

JAVA / / 2022. 2. 23. 23:59

PCR 검사 가능 병원 조회 - ex05

반응형

다섯 번째 테스트 목적 : DB에 List<Hospital> INSERT 하기

 

 

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
System.out.println("1. DB 연결성공");

 

String sql = "INSERT INTO hospital(id, yadmNm, pcrPsblYn, addr) VALUES(seq_hospital.nextval, ?, ?, ?)";

 

for문 안에서 pstmt.executeUpdate( )를 호출해서는 안된다.

executeUpdate는 내부적으로 COMMIT을 하기 때문에

5000번 이상 totalCount동안 INSERT를 하며

I/O가 발생하게 되기 때문이다.

 

이때 쿼리를 모아 한 번에 INSERT문을 전송해서

COMMIT도 한번에 하는 프로그램을 만들어야 한다.

 

이게 배치 프로그램이다.

List<Hospital> hospitals = migration();
PreparedStatement pstmt = conn.prepareStatement(sql); // 내부적으로 new하는 것!

for (Hospital hospital : hospitals) {
    pstmt.setString(1, hospital.getYadmNm());
    pstmt.setString(2, hospital.getPcrPsblYn());
    pstmt.setString(3, hospital.getAddr());

    // pstmt에 쿼리만 하나 들어온다.
    pstmt.addBatch(); // 버퍼에 담기
    // 항아리에 담고나서 쿼리문 초기화
    pstmt.clearParameters(); // 완성된 쿼리를 원복(이유 : pstmt 한개만 쓸거니까)
}

 

 

pstmt.addBatch( )를 호출하면

pstmt.setString으로 완성시킨 쿼리문 하나가

배치 항아리에 담긴다.

 

이 항아리가 버퍼이다.

버퍼에 SQL문 5682개를 담아두는 것이다.

 

항아리에 쿼리를 하나씩 담아두고

모든 쿼리가 다 담겼을 때

한번에 INSERT 하기 위해 담아두는 것이다.

 

배치를 한방에 하기 위해

conn을 for문 밖에 하나만 만들었는데,

for문이 시작하고 ?(물음표)를 채워서

첫 번째 SQL 쿼리가 완성이 되고

addBatch로 항아리에 첫번째 완성 쿼리가 담기게 된다.

 

그리고 두 번째 for문이 돌 때

물음표가 있는 쿼리를 완성하려고

원래 있던 공간을 가리키고 있는 pstmt를 보니

이미 쿼리문이 완성되어 있어서 수정이 불가능하다.

 

첫 번째 for문으로 1번 쿼리는 어차피 항아리에 담겨있으니

쿼리를 최초 상태로 원복 해주면 된다.

 

그러면 완성되지 않은 쿼리로 돌아가, 초기화가 가능해진다.

 

이때 clearParameters( ) 메서드를 사용한다.

 

 

모든 쿼리가 항아리에 다 담기게 되면

한 번에 전송하여 commit 하는

executeBatch( ) 메서드를 호출한다.

pstmt.executeBatch(); // 항아리에 담긴걸 한번에 전송 후 commit
pstmt.close();

 


 

package site.metacoding.hospapp.ex05;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;

// 목적 :  DB에 List<Hospital> INSERT하기   
public class DBInsertTest {

    // 몇개 다운로드 받을지 먼저 totalCount 확인하기
    public static int getTotalCount() {

        int totalCount = 0;

        try {

            // 1. URL 주소 만들기 - totalCount 확인용
            StringBuffer sb = new StringBuffer();

            sb.append("http://apis.data.go.kr/B551182/rprtHospService/getRprtHospService");
            sb.append("?serviceKey="); // 서비스키
            sb.append("서비스키%3D%3D");
            sb.append("&pageNo=?"); // 몇번째 페이지 인지
            sb.append("1");
            sb.append("&numOfRows=");
            sb.append("2"); // totalCount 체크만 할 것이기 때문에 2개만 받아도 된다. (왜 2개냐면 1개만 받으면 List가 아니라 Object로 받더라)
            sb.append("&_type=");
            sb.append("json"); // 데이터 포맷은 JSON

            // 2. 다운로드 받기 - totalCount 확인용

            URL url = new URL(sb.toString());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"));

            StringBuffer sbDownload = new StringBuffer(); // 통신결과 모아두기
            while (true) {
                String input = br.readLine();
                if (input == null) {
                    break;
                }
                sbDownload.append(input);
            }

            // 3. 검증 - totalCountCheck
            // System.out.println(sb.toString());

            // 4. 파싱
            Gson gson = new Gson();
            ResponseDto responseDto = gson.fromJson(sbDownload.toString(), ResponseDto.class);

            // 5. totalCount 담기
            totalCount = responseDto.getResponse().getBody().getTotalCount();
            System.out.println("totalCount : " + totalCount);
            return totalCount;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return totalCount;
    }

    // KISS하게 만드는 것이 좋다. Keep It Small(Short) and Simple
    // totalCount 기반으로 전체 데이터 다운로드한 후 자바 오브젝트로 파싱하기
    public static ResponseDto download() {

        ResponseDto responseDto = null;

        try {
            // 6. 전체 데이터 받기
            // (1) URL 주소 만들기
            int totalCount = getTotalCount();

            if (totalCount == 0) {
                System.out.println("totalCount를 제대로 받지 못하였습니다.");
                return null;
            }

            StringBuffer sb = new StringBuffer();

            sb.append("http://apis.data.go.kr/B551182/rprtHospService/getRprtHospService");
            sb.append("?serviceKey="); // 서비스키
            sb.append("서비스키%3D%3D");
            sb.append("&pageNo=?"); // 몇번째 페이지 인지
            sb.append("1");
            sb.append("&numOfRows=");
            sb.append(totalCount); // totalCount 체크만 할 것이기 때문에 2개만 받아도 된다. (왜 2개냐면 1개만 받으면 List가 아니라 Object로 받더라)
            sb.append("&_type=");
            sb.append("json"); // 데이터 포맷은 JSON

            // (2) 다운로드 받기
            URL url = new URL(sb.toString());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"));

            StringBuffer sbDownload = new StringBuffer(); // 통신결과 모아두기
            while (true) {
                String input = br.readLine();
                if (input == null) {
                    break;
                }
                sbDownload.append(input);
            }

            // (3) 파싱
            Gson gson = new Gson();
            responseDto = gson.fromJson(sbDownload.toString(), ResponseDto.class);

            // 7. 사이즈 검증
            System.out.println("아이템 사이즈 : " + responseDto.getResponse().getBody().getItems().getItem().size());
            System.out.println("totalCount : " + totalCount);
            if (responseDto.getResponse().getBody().getItems().getItem().size() == totalCount) {
                System.out.println("성공~~~~~~~~~~~~~~~~");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return responseDto;
    }

    public static List<Hospital> migration() {
        ResponseDto responseDto = download();
        List<Item> list = responseDto.getResponse().getBody().getItems().getItem();

        List<Hospital> hospitals = new ArrayList<>(); // hospitals에 list로 옮기면 끝

        for (Item item : list) {
            Hospital hs = new Hospital();
            // copy의 목적 : 다른타입의 item을 받아서 Hospital에 복제하여 넣는 것
            hs.objectCopy(item);
            hospitals.add(hs);
        }

        // 검증
        System.out.println("마지막 병원 주소 : " + hospitals.get(5681).getYadmNm());

        return hospitals;
    }

    public static void main(String[] args) {
        try {
            Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
            System.out.println("1. DB 연결성공");

            String sql = "INSERT INTO hospital(id, yadmNm, pcrPsblYn, addr) VALUES(seq_hospital.nextval, ?, ?, ?)";

            List<Hospital> hospitals = migration();
            PreparedStatement pstmt = conn.prepareStatement(sql); // 내부적으로 new하는 것;

            for (Hospital hospital : hospitals) {
                pstmt.setString(1, hospital.getYadmNm());
                pstmt.setString(2, hospital.getPcrPsblYn());
                pstmt.setString(3, hospital.getAddr());

                // pstmt에 쿼리만 하나 들어온다.
                pstmt.addBatch(); // 버퍼에 담기
                // 항아리에 담고나서 쿼리문 초기화
                pstmt.clearParameters(); // 완성된 쿼리를 원복(이유 : pstmt 한개만 쓸거니까)
            }

            pstmt.executeBatch(); // 항아리에 담긴걸 한번에 전송 후 commit
            pstmt.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 

 

[출처]

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com


메타 코딩 유튜브
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

반응형