-
자바로 DB 연동해서 작업하기 Statement 활용 예제프로그래밍/JAVA 자바 2021. 8. 27.반응형
보통 Statement보다 PreparedStatement를 사용한다.
여기선 Statement 사용
자바로 입력해서 오라클 데이타 베이스 서버에 값(데이터)들을 넣고
그 데이터들을 이용해서 자바에서 리스트를 불러오거나 삭제하거나 수정하거나 할거임.
package score1; public class ScoreDTO { private String hak; private String name; private String birth; private int kor; private int eng; private int mat; private int tot; private int ave; private int rank; public String getHak() { return hak; } public void setHak(String hak) { this.hak = hak; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getBirth() { return birth; } public void setBirth(String birth) { this.birth = birth; } public int getKor() { return kor; } public void setKor(int kor) { this.kor = kor; } public int getEng() { return eng; } public void setEng(int eng) { this.eng = eng; } public int getMat() { return mat; } public void setMat(int mat) { this.mat = mat; } public int getTot() { return tot; } public void setTot(int tot) { this.tot = tot; } public int getAve() { return ave; } public void setAve(int ave) { this.ave = ave; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } }
ScoreDTO 클래스
먼저 자바에서 사용할 한 사람에 대한 변수들을 담은 클래스를 만든다.
private니까 꼭 게터세터 이용할것.
package score1; import java.sql.SQLException; import java.util.List; public interface ScoreDAO { public int insertScore(ScoreDTO dto) throws SQLException; public int updateScore(ScoreDTO dto) throws SQLException; public int deleteScore(String hak) throws SQLException; public ScoreDTO readScore(String hak); public List<ScoreDTO> listScore(); public List<ScoreDTO> listScore(String name); }
ScoreDAO 인터페이스 클래스
값을 DB에 등록하고 삭제하고 수정하기 위해서
3개의 함수를 잡는다. 커스텀 예외도 사용할거니까 throws 통해서 이름은 내 맘대로 SQLException 선언
그리고 전체 리스트 출력 위해서 1개 리스트에서 이름 검색용 1개 해서 총 2개의 listScore 선언
=> 전체 리스트는 list형태로 전체를 출력할거라서 list 사용
마지막으로 학번검색용 readScore 선언 => 객체 통해서 한사람 분 출력할거라서 ScoreDTO 형태임
package score1; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import db.util.DBconn; public class ScoreDAOImpl implements ScoreDAO { private Connection conn = DBconn.getConnection(); @Override public int insertScore(ScoreDTO dto) throws SQLException { // TODO Auto-generated method stub int result = 0; Statement stmt = null; String sql; // INSERT INTO 테이블명(컬럼,컬럼) VALUES(값,값) try { sql = "INSERT INTO score(hak, name, birth, kor, eng, mat) VALUES("+ " '"+dto.getHak()+"','"+dto.getName()+"','"+ dto.getBirth()+"',"+ dto.getKor()+","+dto.getEng()+","+dto.getMat()+")"; // 날짜 등록에 문제가 생기면 TO_DATE로 날짜 변환 해주자 stmt = conn.createStatement(); // DML(INSERT, UPDATE, DELETE), DDL(CREATE, ALTER, DROP) 실행 result = stmt.executeUpdate(sql); } catch (SQLIntegrityConstraintViolationException e) { // 기본키 중복, NOT NULL등의 제약조건 위반에 의한 예외 // 에러 코드는 오라클 기준 if(e.getErrorCode() == 1) { System.out.println("학번 중복 입니다."); } else if(e.getErrorCode() == 1400) { // NOT NULL 위반 System.out.println("필수 사항 입력 안함"); } else { System.out.println(e.toString()); } throw e; // 예외 던짐 } catch (SQLDataException e) { // 날짜 등의 형식 잘못으로 인한 예외 if(e.getErrorCode() == 1861 || e.getErrorCode() == 1840) { System.out.println("날짜 형식이 잘못 되었음"); } else { System.out.println(e.toString()); } throw e; } catch (SQLException e) { e.printStackTrace(); throw e; } finally { if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return result; } @Override public int updateScore(ScoreDTO dto) throws SQLException { // TODO Auto-generated method stub int result = 0; Statement stmt = null; String sql; // UPDATE SET WHERE 쿼리 형식임 try { sql = "UPDATE score SET name ='"+dto.getName()+"', birth = '"+dto.getBirth()+ "', kor = " +dto.getKor()+",eng =" +dto.getEng() + ", mat ="+ dto.getMat()+" WHERE hak ='"+dto.getHak()+"'"; stmt = conn.createStatement(); result = stmt.executeUpdate(sql); } catch (SQLIntegrityConstraintViolationException e) { if(e.getErrorCode() == 1400) { System.out.println("필수 입력 사향을 입력 안했음"); } else { System.out.println(e.toString()); } throw e; } catch (SQLDataException e) { if(e.getErrorCode() == 1840 || e.getErrorCode() == 1861) { System.out.println("날짜 형식 올바르지 않음"); } else { System.out.println(e.toString()); } throw e; } catch (SQLException e) { e.printStackTrace(); throw e; } finally { if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return result; } @Override public int deleteScore(String hak) throws SQLException { // TODO Auto-generated method stub int result = 0; Statement stmt = null; String sql; try { sql = "DELETE FROM score WHERE hak = '"+hak+"'"; stmt = conn.createStatement(); result = stmt.executeUpdate(sql); } catch (SQLDataException e) { e.printStackTrace(); throw e; } finally { if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return result; } @Override public ScoreDTO readScore(String hak) { ScoreDTO dto = null; Statement stmt = null; ResultSet rs = null; String sql; // 학번에 만족하는 레코드 가져오기 // SELECT 컬럼, 컬럼 FROM 테이블명 WHERE 조건 try { sql = "SELECT hak, name, TO_CHAR(birth,'YYYY-MM-DD') birth, kor, eng, mat, kor+eng+mat tot,(kor+eng+mat)/3 ave " +" FROM score WHERE hak = '"+hak+"'"; stmt = conn.createStatement(); rs = stmt.executeQuery(sql); // 기본키 조건에 만족하는 레코드는 1개 또는 0개 if(rs.next()) { dto = new ScoreDTO(); dto.setHak(rs.getString("hak")); dto.setName(rs.getString("name")); dto.setBirth(rs.getString("birth")); dto.setKor(rs.getInt("kor")); dto.setEng(rs.getInt("eng")); dto.setMat(rs.getInt("mat")); dto.setTot(rs.getInt("tot")); dto.setAve(rs.getInt("ave")); } } catch (Exception e) { e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (Exception e2) { // TODO: handle exception } } if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return dto; } @Override public List<ScoreDTO> listScore() { // TODO Auto-generated method stub List<ScoreDTO> list = new ArrayList<ScoreDTO>(); Statement stmt = null; ResultSet rs = null; StringBuilder sb = new StringBuilder(); // score 테이블의 모든 레코드 가져오기 (보통 모든 레코드 한번에 가져오는짓 안함) 레코드 = 한줄 // SELECT 컬럼, 컬럼 FROM 테이블명 // VARCHAR2, CLOB는 String으로 넘겨받음 // NUMBER는 int, long, double, Integer, String으로 넘겨받음 (단 null일때 int로 받으면 에러뜸, NPL사용 해야함) // DATE는 java.sql.Date로 넘겨 받는다. (String으로도 가능 근데 yyyy-mm-dd hh:mi:ss 형식으로 넘어옴, 국가별 설정 영향 받음) // TO_CHAR(날짜, 'YYYY-MM-DD') 로 내가 원하는 형식으로 넘겨 받을 수 있음 try { sb.append("SELECT hak, name, birth, kor, eng, mat, "); sb.append(" kor+eng+mat tot, (kor+eng+mat)/3 ave, "); sb.append(" RANK() OVER(ORDER BY (kor+eng+mat) DESC ) rank "); sb.append(" FROM score "); stmt = conn.createStatement(); rs = stmt.executeQuery(sb.toString()); // 테이블의 모든 레코드(한줄)을 읽어 List에 저장 while(rs.next()) { ScoreDTO dto = new ScoreDTO(); dto.setHak(rs.getString("hak")); //dto.setHak(rs.getString(1)); dto.setName(rs.getString("name")); dto.setBirth(rs.getString("birth").toString()); dto.setKor(rs.getInt("kor")); dto.setEng(rs.getInt("eng")); dto.setMat(rs.getInt("mat")); dto.setTot(rs.getInt("tot")); dto.setAve(rs.getInt("ave")); dto.setRank(rs.getInt("rank")); list.add(dto); } } catch (SQLException e) { e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (Exception e2) { // TODO: handle exception } } if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return list; } @Override public List<ScoreDTO> listScore(String name) { // TODO Auto-generated method stub List<ScoreDTO> list = new ArrayList<ScoreDTO>(); Statement stmt = null; ResultSet rs = null; String sql; try { sql = "SELECT hak, name, birth, kor, eng, mat FROM score" // + " WHERE name LIKE '%' || '" + name + "' || '%' "; + " WHERE INSTR(name, '" + name +"')>0"; //2가지 방법 = LIKE, INSTR stmt = conn.createStatement(); rs = stmt.executeQuery(sql); while(rs.next()) { ScoreDTO dto = new ScoreDTO(); dto.setHak(rs.getString("hak")); dto.setName(rs.getString("name")); dto.setBirth(rs.getDate("birth").toString()); dto.setKor(rs.getInt("kor")); dto.setEng(rs.getInt("eng")); dto.setMat(rs.getInt("mat")); list.add(dto); } } catch (Exception e) { e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (Exception e2) { // TODO: handle exception } } if(stmt != null) { try { stmt.close(); } catch (Exception e2) { // TODO: handle exception } } } return list; } }
작성했던 인터페이스를 재정의 하기 위한 ScoreDAOImpl 클래스 ScoreDAO를 상속받는다.
(인터페이스 상속에는 implements 사용)
실질적인 모든 작업은 이 클래스에서 일어남 => DB연결도 해야함.
- DB연결 위해서 Connection 객체 생성 (재정의할 함수 대부분의 곳에서 사용하기 때문에 최상단 위치)
(insertScore 함수)
- 사용자 정의 예외 사용하기 위해서 throws 사용
- 이름대로 등록할 함수이기 때문에 sql 변수에 테이블에 값 등록하는 쿼리문 입력
- 들어가는 값은 입력 받아야 하니까 변수로 사용하고 이따가 UI 구현 클래스에서 ScoreDAO 객체 생성할거니까
(객체 이름 동일 해야함) dto라고 미리 주고 쿼리문 자바 형식에 맞춰서 잘 작성
- SQL문 결과 받기 위해서 Connection conn 객체의 createStatement() 작성
- 쿼리 실행을 위해서 Statement의 executeUpdate생성 하는데 () 괄호 안에 sql 넣어줘야 함.
(sql 변수에 있는 오라클 쿼리 명령어들을 전체적으로 실행하기 위해서)
- result 변수에 쿼리 실행한 결과 값을 저장하고 반환 시킨다.
- catch 부분에서 다양한 에러에 대응해서 미리 작성한다.
- 아까 미리 선언했던 예외를 사용하기 위해서 throw e 를 통해서 커스텀 예외를 발동 시키자.
- 그리고 finally로 꼭 colse() 해주기
(updateScore 함수)
- 위에 인서트스코어 함수랑 별반 차이 없고, sql에 넣는 쿼리문이 다르다
- 오라클에서 값 수정하기 위해서는 UPDATE SET WHERE 형태를 사용했다.
- 마찬가지로 result에 값 넣어주고 반환 시킨다.
- 그리고 finally로 꼭 colse() 해주기
(deleteScore 함수)
- 이것도 별 차이 없음
- 오라클에서 값 삭제를 위해서 DELETE를 사용함 조건으로 학번을 사용함
- 그리고 finally로 꼭 colse() 해주기
(readScore 함수)
- 학번 받아서 해당하는 레코드(쿼리 한줄)가져 오기
- DB에서 값 가져와야 하니까 ResultSet 사용
- sql에는 역시 쿼리 명령문 작성 가져올 값은 학번, 이름, 생일 등등
- ResultSet 객체 rs에 결과 값 담아준다.
- 근데 ScoreDTO 형태를 반환 시켜야 하니까 이 결과 값들을 DTO에 담아주자
- ResultSet의 값들을 불러오기 위해서 next() 사용
- ScoreDTO의 객체가 없으니까 생성해주고
- DTO의 객체 dto.set 명령어를 이용해서 값들을 전부 넣어주자. (rs 결과 값에서도 해당하는
값 가져와야 하니까 get사용)
- 그리고 finally로 꼭 colse() 해주기
(매개 변수 없는 listScore() 함수)
- 이건 모든 리스트 출력에 사용할거니까 List 사용
- ArrayList 이용할거니까 객체 생성
- StringBuilder = String 끼리 더할때 부하 생기는걸 최소화 하기 위해서 사용
(긴 문자열들 서로 결합 시킬때 사용하면 좋다.)
이걸 왜쓰냐면 오라클 쿼리 명령문이 길어서 그렇다.
- DB에서 학번, 이름 등등 성적 총합, 평균, 석차도 구할거고, 총합순으로 내림차순도 할거라서
명령문이 많이 길다.
- 이 쿼리 명령문을 StringBuilder의 객체 sb에 저장해준다.
- append를 쓴 이유는 한줄에 한번에 다 입력해도 되지만 이렇게 나눠서 넣어도 된다
어차피 append는 마지막 위치에 들어가기 때문에 결국 합쳐놓고 보면 한줄이다.
- 쿼리 결과 값 ResultSet에 저장
- 얘도 마찬가지로 List를 반환 해야하는데 List가 ScoreDTO형태니까 DTO객체 만들어서 거기다 값 넣어주고
- 그 DTO에 있는 모든 값들을 리스트에 넣어야 한다.
- 때문에 DTO 객체 dto 생성 및 ResultSet의 값들 돌려주기 위해서 next() 사용하고 dto에 값들 넣어주고
- 마지막에 dto에 있는 모든 값들을 list에 추가한다.
- 그럼 이따 UI에서는 이 list를 받아서 list 출력만 해주면 전체 리스트가 나온다.
- 그리고 finally로 꼭 colse() 해주기
(매개 변수 있는 listScore() 함수) 매개변수가 name
- name 즉 이름을 받아서 그 이름에 해당하는 데이터들을 출력 하는게 목적
- 얘도 형태가 List에 제네릭은 ScoreDTO다
- 얘는 쿼리 명령문이 짧아서 StringBuilder 사용 안함
- 이름을 다 입력하는게 아니라 이름에 있는 글자만 쳐도 나오게 하기 위해서 오라클 쿼리 명령문 LIKE나 INSTR을 사용
(정확한 이름을 입력 받지 않아도 "홍길동" 이라는 이름중에서 "홍"이나 "길" 아니면 "동"만 입력해도 나오게 하는것)
LIKE 사용할거면 '%' 사용 / INSTR는 인덱스 위치 반환
- 마찬가지로 값들 돌려주기 위해서 next() 사용함
- 그리고 객체 생성해서 넣어주고 마지막에 list에 추가
- 그리고 finally로 꼭 colse() 해주기
package score1; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.List; import db.util.DBconn; public class ScoreUI { private BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); private ScoreDAO dao = new ScoreDAOImpl(); public void menu() { int ch; while(true) { try { do { System.out.println("1.등록 2.수정 3.삭제 4.학번검색 5.이름검색 6.리스트 7.종료 => "); ch = Integer.parseInt(br.readLine()); } while(ch<1 || ch>7); if(ch == 7) { DBconn.close(); return; } switch(ch) { case 1 : insert(); break; case 2 : update(); break; case 3 : delete(); break; case 4 : findByHak(); break; case 5 : findByName(); break; case 6 : listAll(); break; } } catch (Exception e) { // TODO: handle exception } } } public void insert() { System.out.println("데이터 등록"); ScoreDTO dto = new ScoreDTO(); try { System.out.println("학번 ? "); dto.setHak(br.readLine()); System.out.println("이름 ? "); dto.setName(br.readLine()); System.out.println("생년월일 ? "); dto.setBirth(br.readLine()); System.out.println("국어 ? "); dto.setKor(Integer.parseInt(br.readLine())); System.out.println("영어 ? "); dto.setEng(Integer.parseInt(br.readLine())); System.out.println("수학 ? "); dto.setMat(Integer.parseInt(br.readLine())); dao.insertScore(dto); System.out.println("데이터 추가 완료"); } catch (NumberFormatException e) { System.out.println("점수는 숫자만 가능합니다."); } catch (Exception e) { System.out.println("데이터 등록 실패"); } System.out.println(); } public void update() { System.out.println("데이터 수정"); String hak; try { System.out.println("수정할 학번"); hak = br.readLine(); ScoreDTO dto = dao.readScore(hak); if(dto == null) { System.out.println("등록된 자료가 없습니다."); return; } System.out.print("수정할 이름 ?"); dto.setName(br.readLine()); System.out.print("생년월일 ?"); dto.setBirth(br.readLine()); System.out.print("국어 ?"); dto.setKor(Integer.parseInt(br.readLine())); System.out.print("영어 ?"); dto.setEng(Integer.parseInt(br.readLine())); System.out.print("수학 ?"); dto.setMat(Integer.parseInt(br.readLine())); dao.updateScore(dto); System.out.println("데이터 수정 완료"); } catch (NumberFormatException e) { System.out.println("점수는 숫자만 가능"); } catch (Exception e) { System.out.println("데이터 수정 실패"); } System.out.println(); } public void delete() { System.out.println("데이터 삭제"); String hak; try { System.out.println("삭제할 학번"); hak = br.readLine(); int result = dao.deleteScore(hak); if(result > 0) { System.out.println("데이터 삭제 완료"); } else { System.out.println("등록된 자료가 아닙니다."); } } catch (Exception e) { e.printStackTrace(); } } public void findByHak() { System.out.println("학번 검색"); String hak; try { System.out.println("검색할 학번 ?"); hak = br.readLine(); ScoreDTO dto = dao.readScore(hak); if(dto == null) { System.out.println("등록된 자료가 없습니다."); return; } System.out.print(dto.getHak() + "\t"); System.out.print(dto.getName() + "\t"); System.out.print(dto.getBirth() + "\t"); System.out.print(dto.getKor() + "\t"); System.out.print(dto.getEng() + "\t"); System.out.print(dto.getMat() + "\t"); System.out.print(dto.getTot() + "\t"); System.out.print(dto.getAve() + "\t"); System.out.println(); } catch (Exception e) { e.printStackTrace(); } } public void findByName() { System.out.println("이름 검색"); String name; try { System.out.println("검색할 이름 ? "); name = br.readLine(); List<ScoreDTO> list = dao.listScore(name); if(list.size() == 0 ) { System.out.println("등록된 자료가 없음"); return; } for(ScoreDTO dto : list) { System.out.print(dto.getHak() + "\t"); System.out.print(dto.getName() + "\t"); System.out.print(dto.getBirth() + "\t"); System.out.print(dto.getKor() + "\t"); System.out.print(dto.getEng() + "\t"); System.out.print(dto.getMat() + "\t"); } System.out.println(); } catch (Exception e) { e.printStackTrace(); } } public void listAll() { System.out.println("전체 리스트"); System.out.println("학번\t이름\t생일\t\t\t국어\t영어\t수학\t총점\t평균\t석차"); System.out.println("======================================================================================="); List<ScoreDTO> list = dao.listScore(); for(ScoreDTO dto : list) { System.out.print(dto.getHak() + "\t"); System.out.print(dto.getName() + "\t"); System.out.print(dto.getBirth() + "\t"); System.out.print(dto.getKor() + "\t"); System.out.print(dto.getEng() + "\t"); System.out.print(dto.getMat() + "\t"); System.out.print(dto.getTot() + "\t"); System.out.print(dto.getAve() + "\t"); System.out.println(dto.getRank()); } System.out.println(); } }
ScoreUI 클래스 (말그대로 눈에 보이는 UI 표시)
- 입력 받아야 하니까 스캐너나 버퍼드리더 사용하는데 여기선 BufferedReader사용함
- 입력 받아야 하니까 InputStreaReader사용
- ScoreDAO의 함수들 가져와서 사용할거니까 객체 만들어 주고
- 눈에 보이는 UI 작성
(insert() 함수)
- 일단 값들 다 DTO객체 dto에 입력받고
- 값 다 들어가있는 dto를 아까 만들었던 ScoreDAOImpl 클래스의 insert 함수 이용해서 DB에 추가하자
(update() 함수)
- 일단 학번이 있는지 없는지 확인해야 하는데 이건 아까 만들어 놨던 ScoreDAOImpl의 readScore 함수 이용
- 만약 학번 있으면 위에 인서트 하는거 처럼 값들 다 입력받고
- 값을 추가가 아니라 수정해야 하니까 ScoreDAOImpl update 함수 호출
(delete() 함수)
- 얘도 형태는 매우 비슷함.
- deleteScore가 1이면 삭제가 된거고 삭제가 안됐으면 0 반환하는걸 이용
(findByHak() 함수)
- 얘는 ScoreDAOImpl의 readScore는 ScoreDTO 즉 한사람분의 데이터가 담겨있는 객체만을 반환하니까
- 출력문은 직접 여기다 소스 작성 해주면 된다.
- 걍 객체 받아온거 출력하는것
(findByName() 함수)
- 얘는 객체가 아니라 리스트가 반환 되어서 오니까
- 리스트 출력을 하면 된다.
(ScoreDAOImpl의 listScore 함수가 리스트를 반환함)
(그러면 여기선 받아온 리스트를 출력 해주면 됨)
(방법은 Iterator 사용하거나 for문 돌리는것)
package score1; public class App { public static void main(String[] args) { // TODO Auto-generated method stub ScoreUI ui = new ScoreUI(); ui.menu(); } }
APP 클래스로 프로그램 작동을 시킨다.
반응형'프로그래밍 > JAVA 자바' 카테고리의 다른 글
자바DB연동 / PreparedStatement 활용 예제 (0) 2021.08.30 입출력 스트림 마무리 (0) 2021.08.29 자바로 오라클 DB 간섭하기 / Statement / ResultSet (0) 2021.08.26 입출력 스트림(6) / PrintStream (0) 2021.08.24 입출력 스트림(5) / File (0) 2021.08.24