초록꼬마의 devlog
article thumbnail

2021.11.29(월)

1. 🌿 Properties를 이용한 JDBC

  • 기존 방식 = JDBC Driver 구문, 내가 접속할 DB의 url 정보, 계정명, 비밀번호를 Java source codes 내에 명시적으로 작성함 = 정적/hard coding 방식 → 나쁜 건 아님, 일 바쁘면/마감시한 촉박하면 이렇게 함, 사고날 일 없고, 편함
    • 문제점 = DBMS가 변경되었을 경우 ou 접속할 url, 계정명, 비밀번호가 변경되었을 경우, Java source codes 수정해야 함 -> 수정한 코드 내용을 반영시키고자 한다면 프로그램을 재구동해야/껐다 켜야 함 -> 사용자 입장에서 프로그램 사용 중 비정상적으로 종료되었다가 다시 구동될 수 있음 -> 유지/보수 불편
  • 해결 방식 = DB 관련된 정보들을 별도로 관리하는 외부 파일(.properties 확장자)로 만들어서 관리, 외부 파일로 key에 대한 value를 읽어들여서 반영시킴 = 동적 coding 방식 -> 유지/보수 용이
    • 설정과 관련된 정보가 외부 파일에 존재 -> DB 관리자 등 Java 코드 모르는/일반 컴퓨터 사용자도 접속 정보를 쉽게 변경 가능
    • "resources/driver.properties"라는 파일(정보)을 읽어들이는 시점 = Connection 객체 생성 시/getConnection() 할 때 = 정보가 필요할 때 -> 프로그램 껐다 켜지 않고도 새로운 정보를 프로그램에 (실시간으로) 반영 가능

✔️ properties 파일 생성

<code />
import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import src.com.kh.view.MemberView; public class Run { public static void main(String[] args) { /* Properties prop = new Properties(); // Properties 객체 하나 생성 -> java.util에 있는 것 import // setProperty() -> Properties 파일 내용 입력 prop.setProperty("A", "B"); // key 'A' + value 'B' prop.setProperty("driver", "oracle.jdbc.driver.OracleDriver"); // 현재 사용하고 있는 Oracle driver 정보를 "driver"라는 key 값에 대응하는 value 값으로 입력 prop.setProperty("url", "jdbc:oracle:thin:@localhost:1521:xe"); // jdbc하면서 사용하고 있는 url = getConnection()의 첫번째 인자 = version + url? + port번호.. prop.setProperty("username", "JDBC"); prop.setProperty("password", "JDBC"); try { // FileOutputStream 객체 생성 시 생성자 매개변수로 경로 제시 vs 별도의 경로 제시가 없으면 프로젝트 폴더 내에 만들어짐 // resources(폴더) = 주로 프로젝트 내의 외부파일들을 저장하는 역할 prop.store(new FileOutputStream("resources/driver.properties"), "driver.properties"); // Properties 객체 생성한 뒤, setProperty()로 값을 넣고 나서, store() -> Properties 파일(외부 매체)에/로 set한 값들을 내보내기; 2개의 매개변수를 받음 = Writer(stream) + String(주석, comments) // Properties 파일 생성 시 위 keys/values 순서 엉망으로 들어감 = Map 계열 특징 -> 파일 열고, 내용 수정하고(내용 순서 수정, \ 삭제 등) 저장하면 반영됨 -> 프로그램 재실행하면 위 set한 것처럼 파일 내용 다시 써짐 -> 파일 한 번 생성(및 수정)한 뒤에는 파일 생성 코드 주석 처리함 prop.storeToXML(new FileOutputStream("resources/query.xml"), "query.xml"); // storeToXML() -> XML 파일로 내보내기 // XML 파일에서는, Properties 파일과 달리, 공백, 줄바꿔쓰기/개행 등 내가 쓰고 싶은대로 쓸 수 있음 // XML 파일로 쿼리문 저장하면, 스트림 만들고 바깥으로부터 파일 불러와서 쓰는 속도(내가 느끼지는 못하겠지만, 훨씬 느림) < 메소드 내에 쿼리문 작성해서 쓰는 속도 } catch (IOException e) { // "surround with try/multi-catch" 예외 처리 자동완성 e.printStackTrace(); } */ new MemberView().mainMenu(); // MemberView 객체 만들어서 더 쓸 일 없으니까, 그냥 기본생성자로 이번 객체 만들고 그 객체의 mainMenu() 메소드에 접근함 } // main() 종료 } // 클래스 영역 끝

✔️ properties 파일 읽기

<code />
public static Connection getConnection() { // 동적 코딩 방식을 적용하기 위해 + Properties 파일 읽기 위해, Properties 객체를 생성 Properties prop = new Properties(); // Connection 객체를 담을 그릇 생성 Connection conn = null; // 연결시키기 = JDBC 단계1,2) try { // load() 메소드 -> 읽기 = prop 객체로부터 load() 메소드를 이용해서 각 키에 해당되는 value 가져오기 prop.load(new FileInputStream("resources/driver.properties")); // Class.forName("oracle.jdbc.driver.OracleDriver"); // 못 박아놓고 사용 = 정적 코딩 방식 Class.forName(prop.getProperty("driver")); // conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC"); // 못 박아놓고 사용 = 정적 코딩 방식 conn = DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"), prop.getProperty("password")); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return conn; // 만든 Connection 객체를 이 메소드 호출한 곳으로 반환 } // getConnection() 종료

2. 🌱 xml 파일 이용

1. 프로젝트 내 resources 폴더에 query.xml 파일 생성

<code />
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>query.xml</comment> <entry key="insertMember"> INSERT INTO MEMBER VALUES (SEQ_USERNO.NEXTVAL , ? , ? , ? , ? , ? , ? , ? , ? , ? , SYSDATE) </entry> <entry key="selectAll"> <!--SELECT USERNO, USERID, USERPWD, USERNAME, EMAIL--> SELECT * FROM MEMBER ORDER BY USERNAME ASC </entry> <entry key="selectByUserId"> SELECT * FROM MEMBER WHERE USERID = ? </entry> <entry key="selectByUserName"> SELECT * FROM MEMBER WHERE USERNAME LIKE ? </entry> <entry key="updateMember"> UPDATE MEMBER SET USERPWD = ? , EMAIL = ? , PHONE = ? , ADDRESS = ? WHERE USERID = ? </entry> <entry key="deleteMember"> DELETE FROM MEMBER WHERE USERID = ? </entry> </properties>

2. Dao 생성자에서 xml 파일 읽어옴

<code />
public class MemberDao { private Properties prop = new Properties(); // properties 객체 생성 + 이 클래스만 사용할 수 있도록 캡슐화(접근제한자 private) // 생성자 내부에 파일 호출하는 코드 작성 -> Dao 객체 생성 시 xml 파일 다시 읽어옴 public MemberDao() { try { prop.loadFromXML(new FileInputStream("resources/query.xml")); } catch (IOException e) { e.printStackTrace(); } } }

3. Dao의 멤버 메서드에서 xml 파일의 key-value 값 가져와서 사용

<code />
public int insertMember(Connection conn, Member m) { // 0) 필요한 변수 먼저 세팅 int result = 0; // 처리된 결과/행의 개수를 담아줄 변수 // Connection 객체는 Service에서 받음 PreparedStatement pstmt = null; // SQL문 실행 후 결과를 받기 위한 변수 // 미완성된 형태의, 실행할, SQL문 String sql = prop.getProperty("insertMember"); // 1,2)는 해서 넘겨받음 try { // 3a) PreparedStatement 객체 생성 + SQL문을 미리 넘겨줌 pstmt = conn.prepareStatement(sql); // 3b) 미완성된 SQL문일 경우 완성시켜주기 // pstmt.setXXX(?의 위치, 실제값) pstmt.setString(1, m.getUserId()); pstmt.setString(2, m.getUserPwd()); ... pstmt.setString(9, m.getHobby()); // 4,5) 완성된 SQL문을 DB에서 실행한 뒤, 결과/처리된 행의 개수 받기 result = pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { // 더 이상 쓸 일/필요 없는 것들의 자원 반납 close(pstmt); } // 6) 트랜잭션 처리는 Connection 객체를 가지고 하는 바, Connection 객체를 만든 Service에서 할 것임 // -> service로 돌아가서 트랜잭션 처리할 때 result 필요하므로 가지고 돌아감 return result; } // insertMember() 종료

2.1. 💻 Statement 이용 + PreparedStatement 및 Properties 이용 조별 실습

"제품 관리 프로그램을 만들어 보자"

  • 실습 파일: 01_JDBC_ProductManager(Statement 이용), 05_JDBC_MiniProject(PreparedStatement 이용)
  • 역할 분담: selectAll(); / insertProduct(); / selectByProductName(); / updateProduct(); (본인 담당) / deleteProduct();와 같이 각 메서드를 조원 1명이 담당 + 공통 모듈(VO, JDBC template, .properties, .xml 등)은 조원 1명이 담당해서 만들고 프로젝트 초반에 공유

📗 homework: JDBC/DBMS 평가 준비