연락처 관리 프로그램 ver.6.0
DAO 인터페이스, DAOImple 클래스, Main 클래스, VO 클래스, Query 인터페이스로 구성됨
- 데이터 모델 : id, name, phone, email
- 기능 : 연락처 등록, 전체검색, 상세검색, 연락처 수정, 연락처 삭제
- UI 구조 :
- 업그레이드 내용 : 데이터베이스와 연결해서 데이터 관리하기.
기존 파일시스템은 리스트를 전역변수로 써서 리스트에 저장된 데이터가 모든 메소드에 영향을 주는 형식이었다면
데이터베이스를 써서 각 기능(메소드)안에서 데이터를 넘겨주고 받는거로 모든 데이터 이동이 끝나게 됩니다.
먼저 데이터베이스에 테이블을 만들어놓고 시작해야해요.
이제 데이터 클래스를 만들면되는데요. 멤버변수는 DB의 데이터를 자바에 가져오는 그릇이기때문에 테이블의 컬럼과 데이터 클래스의 멤버변수는 동일해야합니다.
private int id;
private String name, phone, email;
기존의 데이터 name, phone, email에서 id가 새로 추가되었습니다. 그러나 사용자에게 데이터를 입력받는건 여전히 name, phone, email 뿐으로 id는 db에서 자동으로 생성되는 시퀀스를 사용할 할거예요.
create sequence contact_seq
MINVALUE 1
MAXVALUE 1000
INCREMENT by 1 start with 1
NOCACHE
NOORDER
NOCYCLE;
시퀀스는 db가 알아서 카운트해주기때문에 VO클래스의 객체를 생성할 때 id 부분은 0(비어있음) 혹은 -1(사용안함)로 처리해야줘야해요
ContactVO vo=new ContactVO(0, name, phone, email);
이제 java에서 데이터를 사용하고 DB에 저장하겠습니다.
데이터베이스와 자바를 연결하려면 JDBC를 사용하면 됩니다.
JDBC의 순서대로 구현했어요.
1. 데이터 베이스 라이브러리를 프로젝트에 추가하기
C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib 잊지마세용
2. DB와 연동하기위해 필요한 상수들을 정의하기
자주쓰는 상수들을 interface로 모아서 정의해주었습니다.
public interface OracleQuery {
// 접속할 오라클 DB 경로
public static final String URL=
"jdbc:oracle:thin:@localhost:1521:xe";
public static final String USER="*****";
public static final String PASSWORD="*****";
//DB 컬럼명
public static final String TABLE_NAME="ex_contact";
public static final String COL_CID="cid";
public static final String COL_NAME="name";
public static final String COL_PHONE="phone";
public static final String COL_EMAIL="email";
//insert, selectIndex, selectAll, update, delete 쿼리 작성
public static final String SQL_INSERT=
"insert into "+TABLE_NAME+
" values(contact_seq.nextval, ?, ?, ?)";
public static final String SQL_SELECT_ALL=
"select * from "+TABLE_NAME+" order by "+COL_CID;
public static final String SQL_SELECT_BY_INDEX=
"select * from "+TABLE_NAME+" where "+COL_CID+" = ?";
public static final String SQL_UPDATE=
"update "+TABLE_NAME+" set "+
COL_NAME+" = ?, "+
COL_PHONE+" = ?, "+
COL_EMAIL+" = ? "+
"where "+COL_CID+" = ?";
public static final String SQL_DELETE=
"delete "+TABLE_NAME+" where "+COL_CID+" = ?";
}
PreparedStatement를 사용하기 위한 쿼리문도 미리 상수도 지정해주었어요.
상수들을 정의한 OracleQuery 인터페이스는 DAO클래스에서 implements해줘야 사용할 수 있습니다.
3. JDBC 드라이버를 메모리에 로드
private ContactDAOImple() {
try {
//db 드라이버 등록
DriverManager.registerDriver(new OracleDriver());
System.out.println("드라이버 등록 성공");
} catch (SQLException e) {
e.printStackTrace();
}
}
생성자에 드라이버를 등록시켜 프로그램을 처음 실행했을 때 메모리에 로드되게끔 해줍니다.
4. DB와 Connection을 맺고 SQL 실행
여기서부터 Connection객체와 PreparedStatement 객체를 사용하는데요 데이터의 이동을 메소드안에서 끝내기 위해 각 메소드마다 연결하고 해제하고를 반복해주었습니다.
@Override //등록-입력된 인스턴스를 저장하고 저장결과 리턴하기
public int insert(ContactVO vo) {
Connection conn=null;
PreparedStatement pstmt=null;
int result=0;
try {
conn=DriverManager.getConnection(URL, USER, PASSWORD);
pstmt=conn.prepareStatement(SQL_INSERT);
pstmt.setString(1, vo.getName());
pstmt.setString(2, vo.getPhone());
pstmt.setString(3, vo.getEmail());
result=pstmt.executeUpdate();
System.out.println(result+"행의 데이터가 추가되었습니다.");
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result; //0이면 실패 1이면 저장성공
}//end insert(ContactVO vo)
@Override //전체검색-전체리스트를 리턴하기
public ArrayList<ContactVO> select() {
ArrayList<ContactVO> list=new ArrayList<ContactVO>();
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try {
conn=DriverManager.getConnection(URL, USER, PASSWORD);
stmt=conn.createStatement();
rs=stmt.executeQuery(SQL_SELECT_ALL);
while(rs.next()) {//행이 존재할때까지
int id=rs.getInt(COL_CID);
String name=rs.getString(COL_NAME);
String phone=rs.getString(COL_PHONE);
String email=rs.getString(COL_EMAIL);
ContactVO vo=new ContactVO(id, name, phone, email);
list.add(vo);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}//end select()
@Override //상세검색-인덱스를 받아서 인덱스의 정보 리턴하기
public ContactVO select(int index) {
ContactVO vo=null;
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
conn=DriverManager.getConnection(URL, USER, PASSWORD);
pstmt=conn.prepareStatement(SQL_SELECT_BY_INDEX);
pstmt.setInt(1, index);
rs=pstmt.executeQuery();
if(rs.next()) { //행이 존재하면
int id=rs.getInt(COL_CID);
String name=rs.getString(COL_NAME);
String phone=rs.getString(COL_PHONE);
String email=rs.getString(COL_EMAIL);
vo=new ContactVO(id, name, phone, email);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return vo;
}//end select(int index)
시퀀스는 1부터 시작되지만 앞번호의 데이터가 사라진다고 시퀀스 번호가 앞당겨지진 않습니다. 데이터가 삭제되어도 시퀀스는 숫자는 그대로 비어있어요. 구조적으로 당연한 것입니다. 게시판 게시글 번호처럼 글이 몇개가 삭제되어도 각 게시글들의 고유 번호들은 그대로 유지되는것처럼요
그래서 기존의 데이터 출력 조건을 list 인덱스번호부터가 아니라 현존하는 id의 데이터만 사용할 수 있기 때문에 연속된 번호로 저장되지 않을 수 있습니다.
int count=dao.select().get(0).getId();
int size=dao.select().size()-1;
if(index>=count && index<=(count+size)){}
@Override //수정-인덱스를 받아서 입력된 인스턴스 저장하고 저장결과 리턴하기
public int update(int index, ContactVO vo) {
int result=0;
Connection conn=null;
PreparedStatement pstmt=null;
try {
conn=DriverManager.getConnection(URL, USER, PASSWORD);
pstmt=conn.prepareStatement(SQL_UPDATE);
pstmt.setString(1, vo.getName());
pstmt.setString(2, vo.getPhone());
pstmt.setString(3, vo.getEmail());
pstmt.setInt(4, index);
result=pstmt.executeUpdate();
System.out.println(result+"행의 데이터가 변경되었습니다.");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result; //0이면 실패 1이면 저장성공
}//end update(int index, ContactVO vo)
@Override //삭제-인덱스를 받아서 저장된 인덱스의 정보 삭제하고 결과 리턴하기
public int delete(int index) {
int result=0;
Connection conn=null;
PreparedStatement pstmt=null;
try {
conn=DriverManager.getConnection(URL, USER, PASSWORD);
pstmt=conn.prepareStatement(SQL_DELETE);
pstmt.setInt(1, index);
result=pstmt.executeUpdate();
System.out.println(result+"행의 데이터가 삭제되었습니다.");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result; //0이면 실패 1이면 저장성공
}//end delete(int index)
sql에서 테이블을 건드리면 데이터 커밋은 필수! 쿼리 테스트할때 sql에서 테이블을 변경했더니 java에서 변경전의 데이터가 그대로 나오더라구요. commit의 중요성을 몸으로 느껴보았습니다..😓
콘솔입출력부터 GUI&데이터베이스까지의 버전업그레이드가 끝났는데요 디테일한 예외처리까지 하고싶은데 쉽지않네요😵 앞으로는 새로운 주제의 프로젝트를 진행해보겠습니다👊