일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 장면정부
- 경기체가
- JDBC생성
- JDBC하는법
- 식민통치
- 연결 리스트
- 스레드 트리
- 고대문학
- 고대가요
- 악장
- 국어
- 애국계몽운동
- 항일운동
- CodeUp
- 제3공화국
- 처음요리
- 자료구조
- 무장투쟁
- framework 개요
- 개항기
- JDBC기초
- framework 기본
- 아마추어요리
- 연결 리스트 응용
- JDBC구조
- 3.1운동
- ... 등등
- 한국_현대사
- 제4공화국
- 향가
- Today
- Total
KKH_RECORDS
JDBC 기본 구조 본문
0) [주의사항]
: 패키지를 참조하는 에러는 [ctrl] + [alt] + [O] 단축기 (Eclipse 기준)을 이용하여 [import [패키지명].[클래스] ;]로 import한다.
한 패키지에서 많은 클래스를 참조할 경우 [import [패키지명].* ;]을 통해 한 패키지 안의 모든 클래스를 로드할 수 있다.
허나 패키지 안의 다른 패키지는 [.*]로 로드하지 못한다.
: 패키지 위치는 필자의 기준으로 설명한 것으로, 다르게 해도 문제되지 않는다.
: 밑의 설명은 .jsp나 .html 등과 같은 View를 사용하지 않는 예제이다.
: 프로젝트 생성 시에 UTF-8 인코딩 작업을 잊지 말자.
1) 기본 클래스를 만들기 : [Whole Project Name].model.vo 패키지
private [자료형] [변수명] ; 을 통해 필요한 변수들을 지정하고,
기본생성자 - 필요한 생성자 - 전체생성자 - getter / setter [- toString]을 생성한다.
(toString은 필수가 아니다. 만들 시에는 @Override를 언급해야 한다.)
2) run 파일 (실행파일, main 메소드)를 생성 : [Whole Project Name].run 패키지
.java 파일 생성 시에 main 생성 여부에 클릭하자.
run 파일에서는 View() 파일을 불러온다.
메인 안에는 다른 사항은 일절 넣지 않기로 하자. Run 안에는 Main이 있으며 Main 안에는 [new 파일명().메소드명() ;]만이 있다.
3) View 파일 생성 : [Whole Project Name].view 패키지
View 클래스 안에는 Scanner와 1)에서 생성한 기본 클래스(초기화는 null로 한다. 여러개일 수도 있다.)를 private로 객체 생성한다.
제일 먼저 만드는 것은 메인 메뉴 view로, 단순히 만든다. (이름은 run에서 작성했던 [메소드명()]과 같아야 한다.)
메뉴번호를 잘못 입력할 시 에러가 나게 할 것이므로 화면 표시와 메뉴번호 입력은 do { } while() 과 같은 반복문 안에 넣자.
반복문 안에 메뉴 화면과 Scanner를 통해 메뉴번호를 입력받고 switch문을 만든다.
아직 switch 안의 내용은 넣지 말고, 정해진 선택지와 default (잘못 입력할 경우) 만을 만들어 놓는다.
종료는 보통 0번으로 메뉴 안에 삽입한다. 0번을 입력하면 종료 메시지를 출력하고 종료하도록 하자.
종료하는 작업은 [break ;] 말고 [do { } whilte(조건) ;]의 조건을 이용하자. [while(메뉴번호 != 0) ;]이다.
4) Controller 파일 생성 : [Whole Project Name].controller 패키지
Controller에서는 Service를 호출한다.
생성 시에 private로 Service와 View를 부르는 객체를 생성한다.
참고로 모든 기능을 Controller에 넣을 필요는 없다. Controller에는 Service - DAO를 통해 DB에 접근할 기능만 넣으면 된다.
Controller의 기능 중 특정 정보를 사용자에게 입력받아야 하는 경우, Controller 자체에서 입력받지 않고 다시 View를 호출한다.
view 안에 정보를 입력받는 메소드를 생성하여 입력받고 view에서 생성한 1)의 기본 클래스에 넣은 뒤 리턴받는다.
여기서 갈리는데, 만약 입력(내가 DB에 입력하여 결과만을 받아옴)의 경우에는
[int result]을 Service로 받은 뒤 이 result를 [return result ;]의 과정을 거치며,
만약 선택(내가 DB에서 값을 추출)의 경우, ArrayList<기본 클래스명>을 이용한다.
service로 값을 받아온 후에는 받아온 값을 검사한다. int값인 경우 값이 1 이상인지 검사하며 ArrayList 일 때 isEmpty()를 이용한다.
값이 정상적으로 받아온 경우 View의 해당하는 성공으로 보내고,
실패한 경우 displayError()라는 메소드를 View에 생성한 후 실패 사유나 결과 등을 같이 보내 사용자에게 출력한다.
5) Service 파일 생성 : [Whole Project Name].model.service 패키지
Service 파일의 역할은 다음과 같다.
1. Controller로부터 인자를 전달 받음
2. Connection 객체 생성
3. DAO 객체 생성
4. DAO에 생성된 객체와 인자 전달
5. DAO의 수행 결과를 이용해 비즈니스 로직 및 트랜잭션 관리
여기서 Connection, close 등 여러 과정을 거쳐야 하는데, 기능마다 이런 내용을 작성하는 것은 불편하므로
JDBCTemplate라는 공통된 과정을 이름으로 불러오는 클래스를 만든 뒤 이를 import static 방식으로 임포트한다.
6) JDBCTemplate 파일 생성 : [Whole Project Name].common 패키지
먼저 기본 생성자를 만든다. 그러나 다른 클래스와 달리 public이 아니라 private로 생성한다.
이는 객체 생성을 불가능하게 한다는 뜻이다.
여기서는 기본생성자를 제외한 다른 생성자 등에 모두 static을 붙인다.
제일 먼저 생성해야 하는 것은 Connection이다. 클래스에 전역변수 Connection conn을 null의 형태로 선언한다.
이후 public static getConnection()을 만든다. 내용은 다음과 같다.
public static Connection getConnection() {
if(conn==null) {
try {
Properties prop = new Properties() ;
prop.load(new FileReader("driver.properties")) ;
Class.forName(prop.getProperty("driver")) ;
conn = DriverManager.getConnection(prop.getProperty("url"),
prop.getProperty("user"),
prop.getProperty("password")) ;
conn.setAutoCommit(false) ;
} catch (ClassNotFoundException e) {
System.out.println("[ERROR] : "+e.getMessage()+"]");
} catch (SQLException e) {
System.out.println("[ERROR] : "+e.getMessage()+"]");
} catch (FileNotFoundException e) {
System.out.println("[ERROR] : "+e.getMessage()+"]");
} catch (IOException e) {
System.out.println("[ERROR] : "+e.getMessage()+"]");
}
} return conn ;
}
Connection 생성 이후 commit, rollback, close도 차례대로 만들어 준다.
public static void commit(Connection conn) {
try {
if(conn != null && !conn.isClosed())
conn.commit() ;
} catch (SQLException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
}
public static void rollback(Connection conn) {
try {
if(conn != null && !conn.isClosed())
conn.rollback() ;
} catch (SQLException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
}
public static void close(Connection conn) {
try {
if(conn != null && !conn.isClosed())
conn.close() ;
} catch (SQLException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
}
public static void close(ResultSet rset) {
try {
if(rset != null && !rset.isClosed())
rset.close() ;
} catch (SQLException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
}
public static void close(Statement stmt) {
try {
if(stmt != null && !stmt.isClosed())
stmt.close() ;
} catch (SQLException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
}
여기에 보면 Properties라는 게 있을 것이다.
이는 다음과 같으며, 이 역시 기본 절차를 생략하기 위해 다른 파일로 작성해 놓은 것이다.
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=MEMBER
password=MEMBER
7) Service 파일 - 2 : [Whole Project Name].model.service 패키지
JDBCTemplate를 생성한 하였으니 이제 내용을 채우도록 하자.
각 메소드마다 필요한 [Connection conn = getConnection() ;]을 사용한다.
getConnection은 위의 JDBCTemplate에서 생성한 것으로,
static 키워드를 사용했으므로 getConnection이라고 부르는 것만으로도 사용할 수 있다.
이 다음에는 MemberDAO를 호출한다.
Controller에서처럼 선택이라면 ArrayList나 기본 클래스로, 입력이라면 int로 받은 뒤 값을 검사한다.
값이 정확히 들어갔다면 commit을, 아니라면 rollback한다.
8) DAO 파일 : [Whole Project Name].model.dao 패키지
DAO(Data Access Object)는 실제로 DB에 접속하여 값을 받는 부분이다.
DAO가 맡은 업무는 다음과 같다.
1) JDBC Driver 등록
2) DB연결 Connection 객체 생성
3) SQL 작성 및 실행
4) 처리 결과에 따른 Transaction 처리 (commit, rollback)
5) 자원 반환
사실 DAO는 3)만을 실행시키고 1),2),4),5)는 다른 곳에서 실행해야 한다. (분리, Service)
클래스 안에 [private Propertites prop = null ;]을 생성한다. 그 후 기본생성자에 prop의 내용을 지정한다.
try {
prop = new Properties() ;
prop.load(new FileReader("query.properties")) ;
} catch(FileNotFoundException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
} catch(IOException e) {
System.out.println(" [ERROR] : "+e.getMessage()+"]") ;
}
여기서 query.properties는 driver.properties와 마찬가지로 SQL Query 파일을 외부에 저장한 것이다.
query.properties에서는 [이름 = 쿼리문]의 형식으로 저장하는데, 사용자의 값에 따라 달라지는 부분은 "?"를 이용한다.
예시 :
insertMember=INSERT INTO MEMBER VALUES(?,?,?,?,?,?,?,?,SYSDATE)
selectAll= SELECT * FROM MEMBER
#selectMbId=SELECT * FROM MEMBER WHERE MEMBER_ID LIKE
selectMbId=SELECT * FROM MEMBER WHERE MEMBER_ID LIKE ?
checkMb=SELECT COUNT(*) FROM MEMBER WHERE MEMBER_ID = ?
여기서 두 가지 경우로 나뉜다.
삽입/수정/삭제 등의 경우 :
PreparedStatement ptmt, int result를 null로 생성한다.
[String query = = prop.getProperty("query.properties의 키워드 입력") ;]를 통해 쿼리문 String을 생성한다.
[ptmt = conn.prepareStatement(query) ;]를 입력하여 ptmt에 query를 할당한다.
여기서 발생하는 에러는 전구 모양 버튼을 눌러 두 번째의 try catch 작업을 한다.
[ptmt.setString("")/setInt("")/setDate("")] 등을 이용하여 ? 에 들어갈 값을 채워준다.
[result = ptmt.excuteUpdate() ;]를 이용하여 쿼리문을 실행시킨다.
catch문이 닫힌 뒤에 finally 키워드를 열고 안에 [close(ptmt) ;]를 입력한다.
finally 문도 닫힌 뒤에 [return result ;]를 입력한다.
선택의 경우 :
PrepraredStatement를 사용하는 경우 (상세보기 등)
Statement를 사용하는 경우 (전체 리스트 보기 등)
p(stmt) 생성 작업을 해준 뒤, ResultSet, ArrayList<~>을 선언하고 쿼리문(String)을 지정한다.
[ptmt = conn.preparedStatement(query) ;] [stmt = conn.createStatement(query) ;]
ptmt의 경우에는 삽입/수정/삭제에서처럼 .set~~() 작업으로 ?에 값를 지정해준다.
[rset = (p)stmt.excuteQuery() ;]작업을 완료한다.
while(rset.next()) { ~ } 안에 내용을 작성한다. rset에서 받아온 값이 있을 때 실행한다는 뜻이다.
rset에 있는 값들을 기본 클래스(1))에 담은 뒤 이 기본 클래스를 ArrayList 안에 담는다.
catch 밖에 finally를 통해 close(rset), close(ptmt) 작업을 한다. 반드시 rset이 먼저 와야 한다.
ArrayList 값을 반환한다.
9) 마무리하며
긴 글 읽어 주셔서 감사합니다.
내용이 부정확할 수 있으며, 이름 등은 달라도 됩니다.
여러분에게 제 자료가 많은 도움이 되었으면 좋겠습니다.
감사합니다.
'Records 1 : Study > JDBC' 카테고리의 다른 글
JDBC workspace 업로드 (0) | 2020.02.15 |
---|---|
JDBC 기본 파일 업로드 (0) | 2020.02.15 |