데이터베이스

JDBC 실습_국비_DAY39

Leo.K 2022. 4. 22. 19:36

오늘은 자바로 만든 성적관리 폼과, DB로 만든 성적관리 데이터를 연동하여 사용해보는 실습을 해보겠습니다. 

전체적인 구조는 다음과 같습니다. 

지난 포스팅에서 selectList를 구현하는 방법에 대해 공부해보았습니다. 내용이 궁금하신 분은 여기를 학습하세요.

이번에는 나머지 insert, update, delete명령의 실행과정을 중심으로 공부해보도록 하겠습니다. 

1. 사전준비

새로운 프로젝트에 드라이버 라이브러리를 불러왔다는 가정 하에, 우선적으로 자바와 연동할 데이터베이스를 설계해야 합니다. 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
--1. 테이블 생성
create table sungtb
(
    idx int,                        --일련번호
    name varchar2(100not null,    --이름
    kor int,                        --국어 
    eng int,                         --영어    
    mat int                         --수학    
 
 
--2. 기본키 설정
alter table sungtb
    add constraint pk_sungtb_idx primary key(idx); 
 
--3. 제약조건 설정 체크제약(국어/영어/수학) : 0~100
alter table sungtb
    add constraint ck_sungtb_kor check(kor between 0 and 100)
    
alter table sungtb
    add constraint ck_sungtb_eng check(eng between 0 and 100)
    
alter table sungtb
    add constraint ck_sungtb_mat check(mat between 0 and 100)
    
--4. 일련번호 관리 객체(시퀀스)
create sequence seq_sungtb_idx
 
--5. sample data 삽입
insert into sungtb values(seq_sungtb_idx.nextVal, '일길동'908070)
insert into sungtb values(seq_sungtb_idx.nextVal, '이길동'908080)
insert into sungtb values(seq_sungtb_idx.nextVal, '삼길동'9010090)
 
--위의 명령이 완전히 완료되었음을 알리기 위한 커밋
commit
 
 
 
--6. 조회시 필요한 view를 생성
create or replace view sungtb_view
as
    select 
        s.*,
        (kor+eng+mat) as tot,
        round((kor+eng+mat)/31) as avg,
        rank() over(order by (kor+eng+mat) desc) as rank --rank를 매기는 순서지정[over(order by ~)]
    from 
        (select * from sungtb) s
        order by idx
 
 
--7. 뷰 생성 확인
select * from sungtb_view
 
 
 
 
 
 
 
cs

 

위의 소스대로 DB를 설계하고 데이터를 삽입하여 왼쪽에 있는 이미지와 같이 사전준비를 해주었습니다.

 

 

위의 보이는 구조와 마찬가지로 자바 윈도우 프로그래밍으로 기본적인 폼을 설정하고 DB에서 읽어온 데이터를 출력하고자 하는데, 먼저 JTabel에 데이터를 연결하는 방법을 숙지해야 합니다.

참고로 전체 코드의 길이가 400줄 이상으로 길기 때문에, 흐름과 함께 주요 메서드의 코드만 조회해보도록 하겠습니다. 

다음과 같이 MVC패턴의 구조로 JTable에 배치를 해보겠습니다. 

controller에 ArrayList구조에 저장된 model의 데이터를 저장하면 controller(SungTableModel)에 정의된 배치방법(AbstractTableModel이라는 추상클래스를 상속받아 그 내부에 정의된 추상메소드를 내가 필요한 방법으로 배치하기 위해 재정의함 )으로 JTable(View)에 배치합니다.

1. 배치모델 초기화하기 display_sung_list()

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
31
32
33
34
35
36
37
38
39
40
41
42
class SungTableModel extends AbstractTableModel{
    
    //타이틀
    String [] title = {"번호""이름""국어""영어""수학""총점""평균""등수"};
    
    
    //행의 개수(데이터의 개수)
    @Override
    public int getRowCount() {
        // TODO Auto-generated method stub
        return sung_list.size();
    }
    
    //타이틀 배치
    @Override
    public String getColumnName(int column) {
        // TODO Auto-generated method stub
        return title[column];
    }
    
    //열의 개수(타이틀 개수)
    @Override
    public int getColumnCount() {
        // TODO Auto-generated method stub
        return title.length;
    }
 
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        // TODO Auto-generated method stub
        SungVo vo = sung_list.get(rowIndex);
        if(columnIndex == 0return vo.getIdx();
        else if(columnIndex == 1return vo.getName();
        else if(columnIndex == 2return vo.getKor();
        else if(columnIndex == 3return vo.getEng();
        else if(columnIndex == 4return vo.getMat();
        else if(columnIndex == 5return vo.getTot();
        else if(columnIndex == 6return vo.getAvg();
        return vo.getRank();
    }
    
}
cs
  • Dao를 통해 전달 받은 데이터 sung_list가 파일 내 어디에서도 사용할 수 있도록 전역으로 선언되어 있습니다.
  • getRowCount() : 읽어온 데이터의 행의 수를 반환합니다. -> 출력할 데이터의 행의 수
  • getColumnCount() : 읽어온 데이터의 열의 수를 반환 합니다. -> 헤딩명[title]의 요소 개수
  • getColumnName(int column) : 읽어온 데이터의 각 열에 해당하는 헤딩명을 매핑해서 반환합니다. 
  • getValueAt(int rowIndex, int columnIndex) : 각 행과 열에 맞는 위치에 적절한 데이터를 입력합니다. 이때, sung_list 의 각 요소에는 vo로 포장된 객체단위로 데이터가 저장되므로, 행 단위로 각 열에 맞는 데이터 값을 입력합니다.

2. JTable에 읽어온 모든 데이터를 배치하기

1
2
3
4
5
6
7
8
private void display_sung_list() {
    // TODO Auto-generated method stub
    //1. DB목록 가져오기 
    sung_list = sungTBDao.getInstance().selectList();
    
    //2. JTable에 배치 
    jtb_display.setModel(new SungTableModel());
}
cs
  • Dao를 통해서 DB에 접근하여 데이터를 읽어옵니다. sung_list 는 데이터가 포장되어 저장된 ArrayList입니다.
  • SungTableModel에서 재정의된 메서드를 통해서 모델의 데이터가 JTable에 배치됩니다. 

 

3. JTextField에 현재 current_pos[Vo의 커서와 비슷한 역할을 합니다.]가 가리키고 있는 행의 데이터를 출력하기 display_input_sung() 데이터의 내용이 변경되어 current_pos의 값이 변경될 때마다 반드시 새로 호출해야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void display_input_sung() {//현재 포지션에 있는 데이터를 가져와서 특정 레코드 값 하나를 읽어서 input창에 출력한다.
        // TODO Auto-generated method stub
        //출력해야 할 SungVo정보를 얻어온다.
        SungVo vo = sung_list.get(current_pos);
        
        jtf_no.setText(vo.getIdx() + " "); // 숫자를 문자열로 바꾸는 방법 1 ; 숫자랑 문자열을 더하기 연산해서 문자열로 만듬
        jtf_name.setText(vo.getName());
        
        jtf_kor.setText(vo.getKor() + " ");
        jtf_eng.setText(String.valueOf(vo.getEng())); //숫자를 문자열로 바꾸는 방법 2
        jtf_mat.setText(vo.getMat() + " ");
 
        jtf_tot.setText(vo.getTot());
        jtf_avg.setText(vo.getAvg());
        jtf_rank.setText(vo.getRank());
        
        
        //JTable에서 행 선택 기능
        jtb_display.setRowSelectionInterval(current_pos, current_pos);
        
        //버튼 활성 유무를 결정
        enable_buttons();
    }    
cs
  • current_pos라는 데이터의 위치를 가리키는 변수가 있습니다. 이는 Vo에서 봤었던 rs의 커서와 같은 기능을 합니다. sung_list는 각 요소에 vo객체로 포장된 한 행의 데이터가 있습니다. 
  • current_pos가 가리키고 있는 vo객체를 읽어와서 JText필드에 값을 출력합니다.

 

4. 이벤트

기본적인 출력작업은 모두 마쳤습니다. 이제는 버튼 이벤트에 대해서 버튼을 눌렀을 때, 수행해야 하는 작업을 코드와 함께 살펴보겠습니다.

1) 버튼을 누르면 데이터가 이동 JTextField에 출력된 데이터가 다음 데이터를 출력하면서 JTable 데이터에서 선택된 행도 함께 이동하도록 구현하는 방법

- 먼저 버튼 눌렀을때 이벤트가 진해되도록 구성되어 있는 on_next메서드에 다음과 같이 코드를 작성해줍니다. 

1
2
current_pos++;
display_input_sung();
cs

위의 코드는 "다음"버튼을 눌렀을 때의 예시 코드이며, "이전" 버튼에 대한 코드는 반대로 current_pos--;를 합니다.

3번 코드를 보시면 맨 하단에 2개의 메소드가 존재하는데 그 내부는 다음과 같습니다. 

  • jtb_display.setRowSelectionInterval(current_pos, current_pos) : 행의 간격을 구하는데 current_pos와 current_pos사이의 간격을 구하는 코드입니다. 출발과 종료가 같으니 당연히 현재 current_pos가 가리키는 행만 선택되게 됩니다. 이때, 다음 or 이전 버튼을 누르면 current_pos의 값이 증가 or 감소하므로 선택된 행도 함께 움직입니다.
  • enable_buttons() : current_pos가 지정된 인덱스 범위를 벗어나면 에러가 발생하기 때문에 맨 마지막 행에서 다음버튼을 누르거나, 맨 처음 행에서 이전 버튼을 누를 수 없도록 버튼을 비활성화 시키는 메소드입니다. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void enable_buttons() {//버튼의 활성화 여부를 토글 방식으로 설정하는 메서드
    //처음이 아니면 활성화
    jbt_prev.setEnabled(current_pos>0 && bAdd == false);
    //마지막 첨자보다 작으면 활성화
    jbt_next.setEnabled(current_pos <( sung_list.size()-1) && bAdd == false);
        
    //삭제버튼 활성 여부 
    jbt_delete.setEnabled((bAdd == false) && sung_list.size() > 0 );
        
    //수정버튼 활성 여부 
    //&&연산을 사용하면 데이터가 없을 때 수정버튼이 비활성화 된다. 데이터가 없으면 추가 버튼을 눌러서 데이터를 삽입해주어야 하는데, 
    //&&연산자를 쓰면 추가작업을 완료하고 등록 버튼을 눌러야 하는데 비활성화 되어서 누를 수가 없다. 수정 버튼이 등록의 기능까지 하기 때문입니다.
    jbt_update.setEnabled((sung_list.size() > 0) || bAdd == true);
}
cs

아직 설명하지 않은 기능에 대한 내용이 있기 때문에 지금은 간단히만 설명하고 해당 내용이 나올때 그 부분에서 자세히 설명토록 하겠습니다. 일단 지금은 다음 버튼은 current_pos 가 현재 가리키고 있는 인덱스가 리스트의 마지막 첨자보다 작을때만, 이전 버튼은 current_pos 가 현재 가리키고 있는 인덱스가 리스트의 첫 첨자보다 클때만 활성화시키는 것입니다.

2) 특정 행을 선택하면 그 행의 데이터를 JTextField에 출력하는 방법

이벤트와 관련해서는 주석만 참고해도 어렵지 않기 때문에 소스만 첨부하고 넘어가겠습니다.

1
2
3
4
5
6
7
8
9
10
11
//마우스 이벤트(JTable에서 마우스가 클릭되면)
jtb_display.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        //super.mousePressed(e);
        //선택된 행을 구한다.
        current_pos = jtb_display.getSelectedRow();
        display_input_sung();
    }
});
cs

 

자, 이제는 selectList()로 읽어온 메소드를 출력하고 데이터를 넘기는 등, 조회를 위한 작업은 모두 끝났습니다. 마무리로 select를 제외한 나머지 CRUD객체 수행명령인 insert, update, delete를 살펴보고 마무리하겠습니다.

데이터의 삽입과, 삭제, 수정 명령에 대한 명령 처리 코드는 sql명령문을 제외하고 같기 때문에 소스코드는 설명 이후 마지막에 필자가 제작한 템플릿을 첨부하겠습니다.

5. 데이터 삽입 insert()

삽입에 대한 소스코드를 작성하기 전에, 마지막으로 버튼에 대해 작업해주어야 할 일이 있습니다. 가장 상단에 필자가 삽입한 그림을 보시면 "추가"버튼과 "수정"버튼이 있는데, 추가버튼을 누른 경우 추가 -> 취소, 수정 -> 등록으로 바뀌도록 설정을 해주겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected void on_new() {
    // TODO Auto-generated method stub
    bAdd = !bAdd;
    
    if(bAdd) {
        //신규등록 준비작업
        clear_input();
    }else {
        //취소
        if(sung_list.size()>0)
            display_input_sung();
    }
    //버튼 캡션(타이틀) 변경
    jbt_new.setText(bAdd ? "취소" : "추가");
    jbt_update.setText(bAdd ? "등록" : "수정");
    
    //수정중에 데이터를 다음이나 이전버튼을 누를 수 없도록 해야합니다. 
    //버튼 활성 유무 (버튼이 눌릴때 적용을 시켜야 바로바로 적용이 됩니다.)
    //버튼이 눌릴때 버튼의 활성화 여부를 갱신할 수 있도록 
    enable_buttons();
    
}
cs
  • bAdd : 토글버튼을 사용할 것인데 기본값은 false인 상태이다.(추가, 수정)
  • 추가 버튼을 누르면 토글기능으로 true를 반환하면서 입력을 받을 준비를 하기 위해 현재 JTextField에 출력되어 있는 값을 빈칸으로 초기화 합니다. 
  • 버튼의 캡션을 변경합니다. false, [추가, 수정]  --->  true, [취소, 등록]
  • 처음 버튼을 눌렀을 때, true가 되었다가, 다시 버튼을 누르면 취소버튼을 누른 것입니다. 따라서 bAdd값이 다시 false로 토글되면서 기본값으로 돌아옵니다. 

그렇다면 아까 4번에 enable_buttons메서드 내부를 다시보면 조건이 And연산자로 이어져 있는데, 위의 그림을 보면 이해가 될 것입니다. 즉, 추가작업을 하는 동안은 버튼을 비활성화하겠다는 뜻입니다.

 

이제 직접 데이터를 입력하고 "등록"버튼을 누르면 된다. 이때, 이 버튼은 bAdd의 값에 따라서 등록을 하거나 수정을합니다. 즉 insert와 update의 명령이 하나의 버튼으로 이루어집니다. 그렇기 때문에 bAdd의 값에 따라서 조건을 분할하여 기능을 수행하도록 해야하는데, 먼저 공통적으로 적용되는 코드를 보자면 기본적으로 입력값에 대한 제약사항을 생각해주어야 합니다.

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
// TODO Auto-generated method stub
//이름 국어 영어 수학의 내용은 반드시 입력되어야 한다. -> 입력사항 체크
String name = jtf_name.getText().trim();
 
if(name.isEmpty()) {
    JOptionPane.showMessageDialog(this"이름을 입력하세요!!!");
    jtf_name.setText("");
    jtf_name.requestFocus();
    return;
}
int kor =0, eng=0, mat=0;
 
//국어 점수 
String str_kor = jtf_kor.getText().trim();
 
try {
    //숫자 인지 체크
    kor = Integer.parseInt(str_kor);//"88a"숫자가 아닌 값이 입력되면 에러
    
    //범위 체크
    if(kor < 0 || kor >100throw new Exception();
catch (Exception e) {
    // TODO: handle exception
    JOptionPane.showMessageDialog(this"국어점수는 0~100사이의 정수만 입력하세요!!!");
    jtf_kor.setText("");
    jtf_kor.requestFocus();
    return;
}
cs
  1. 입력된 문자열이 공백라면? 
    1. 안내메시지
    2. 입력 칸 비우기
    3. 입력해야 하는 칸에 포커스 두기
  2. 입력된 값이 숫자가 아닌 문자가 포함되어 있다면? 처음 JTextField에 출력할 때, 문자열 형식으로 출력했기 때문에 반드시 정수형으로 변환하는 과정을 먼저 거쳐야 합니다. 
    1. 정수로 바꾸는 과정에서 문자열이 숫자로만 구성되어 있지 않다면 --> 1과 같은 에러 처리
    2. 값의 범위가 0 - 100사이의 값이 아니라면 --> 1과 같은 에러처리

위의 조건을 마쳤다면 이제 실질적으로 데이터를 추가하겠습니다. 데이터를 추가하는 것은 다음과 같은 순서로 진행해야합니다. 

  • 추가하기 위해 입력받은 데이터를 Vo 클래스로 포장합니다
  • 포장한 데이터를 Dao에게 넘겨주어 insert()메소드를 실행할 수 있도록 합니다. 
  • int res = sungTBDao.getInstance().insert(vo); 이와 같은 형식으로 삽입 명령을 실행하는데, 삽입 메소드 내부에서 명령을 처리한 행의 수를 res라는 변수에 담아서 반환합니다. 하지만 삽입의 경우 1번의 1문장이 실행되는 프로그램이기 때문에 res는 반드시 1이 나옵니다. 단, res=0이라면 삽입명령이 정상 수행되지 않았음을 알 수 있습니다.
  • display_sung_list(); 읽어온 데이터를 JTable에 배치하는 메소드 입니다. 즉, 데이터를 삽입하고 DB에서 새롭게 데이터를 읽어와야 합니다. 프로그램은 이름과 점수를 입력하면 합계와 평균 "등수"를 계산해주는데 삽입된 명령으로 인해 기존에 있던 데이터들의 값이 바뀌기 때문입니다. 이는 수정과 삭제 연산 또한 마찬가지입니다. 
  • current_pos = sung_list.size()-1; 새로운 데이터는 기존 데이터의 가장 마지막 행에 추가됩니다. 
  • 등록과정을 마쳤으니 버튼의 캡션과 bAdd를 다시 기본값으로 돌려줍니다. 
  • current_pos의 값이 바뀌었으니 display_input_sung();새롭게 호출합니다.

혹여나 데이터를 입력했는데 시퀀스 번호가 1, 2, 3, 21, 22 이렇게 나오는 경우가 있을 수 있습니다. 이는 DB서버가 계속 켜진 상태로 돌아가야 하는데, 프로그램을 껐다가 켜면 연결이 끊어졌다가 다시 연결하게 됩니다. 이때, 끊긴 시간이 길어지면 오라클이 자체적으로 시퀀스 번호를 재설정합니다. 이는 오류가 아닙니다. 

6. 데이터 수정 update() & 데이터 삭제 delete(int idx)

데이터를 수정하고 삭제하는 연산은 기존의 있던 데이터의 변경을 의미합니다. 이는 다시 돌리기 쉽지 않은 명령으로, 사용자가 충분히 실수할 수 있는 연산이기 때문에 명령을 실행하기 전에 다음과 같이 반드시 정말 수행할 것인지 물어봐야 합니다. 

1
2
3
4
5
6
7
8
int result = JOptionPane.showConfirmDialog(this"정말 수정하시겠습니까?""수정", JOptionPane.YES_NO_OPTION);
            
    //예스 버튼이 아니면 끝내라
    if(result != JOptionPane.YES_OPTION) {
        //원래값 돌려 놓기 
        display_input_sung();
        return;
    }
cs

실제로 수정하는 작업은 삽입 명령과 비슷합니다. 

  • jtf_no:번호가 저장된 문자열을 읽어서 idx변수에 넣어줍니다. 이때 문자열에 공백을 제거해야합니다. 
  • 기존 내용을 포함하여 수정된 내용 전체 데이터를 Vo객체로 포장합니다. 이때 반드시 번호(=idx)값을 추가해주셔야 수정명령을 할때 조건절에 사용할 수 있습니다. [Vo에 오버로드 생성자를 만들어서 한 번에 포장해도 됩니다.]
  • int res = sungTBDao.getInstance().update(vo) Dao에게 SQL 처리 명령을 부탁합니다. 
  • display_sung_list(); 수정 명령 또한 값이 바뀜으로써 전체적인 데이터의 변화가 생기므로 데이터를 새롭게 읽어옵니다.
  • display_input_sung() -> current_pos의 값이 바뀌었으니 현재 가리키고 있는 행의 데이터를 새롭게 출력합니다.

삭제 또한 위와 같이 삭제 명령을 수행하기 이전에 최종확인을 합니다. 

삭제명령은 데이터를 삭제만 하면 되기 때문에 데이터를 포장할 필요는 없고, 삭제하고자 하는 레코드의 기본키값인 번호를 delete메소드의 인자로 넘겨 줍니다. 단, 삭제 메소드는 두가지를 더 고려해주어야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//삭제하기 
int idx = Integer.parseInt(jtf_no.getText().trim());
 
//1. DB 삭제(삭제 명령은 조건절에 사용할 idx만 있으면 된다.)
int res = sungTBDao.getInstance().delete(idx);
 
//2. 전체 데이터 가져오기
display_sung_list();
 
//2-1. 데이터가 남아있는지 유무를 확인하라. sung_list = 0이면 없음
//데이터가 1개 남았을때, 삭제하는 경우 -> clear_inputs
if(sung_list.size()==0) {
    clear_input();
    enable_buttons(); //데이터가 없으므로 삭제버튼을 누르지 못하도록 해야 한다.
    return;
}
 
//2-2. 현재 삭제한 데이터가 마지막이었냐? 현재 current_pos이 어디 있는지 확인해야 한다.
//current_pos > size인 경우 current_pos--; 
if(current_pos == sung_list.size())
    current_pos--;
 
//3. 입력창 출력
display_input_sung();
cs

삭제 메소드를 호출하여 삭제 명령을 진행한 후에 다음 두 가지를 고려합니다

1. 삭제후에 남아있는 데이터가 없다면 JTextField를 초기화합니다.

2. 삭제 후에 전체 데이터를 가져왔는데 방금 삭제한 데이터가 가장 마지막 행이었다면, 현재 current_pos의 위치를 확인하고 -1해주어야 합니다. 삭제 명령후 current_pos의 위치는 가장 마지막 행을 보고 있었는데 데이터가 하나 줄어들면서 current_pos가 지켜보던 행은 없는 값. 즉, outofindex가 되기 때문에 -1을 해주어야 합니다. 그림을 보면 쉽게 이해하실 수 있을 겁니다. 

7. insert/update/delete 템플릿

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
31
32
public int insert_update_delete(${cursor} vo) {//버튼을 누름으로써 자바에게 전달받은 vo
        // TODO Auto-generated method stub
        int res = 0;
        Connection         conn = null;
        PreparedStatement pstmt = null;
        
        String sql = "";
        try {
            //1. Connection얻어오기
            conn = DBService.getInstance().getConnection();
            //2. 명령 처리 객체 얻어오기
            pstmt = conn.prepareStatement(sql);
            //3. pstmt의 파라미터 설정//데이터의 자료형을 필히 파악하라!//문자던 숫자던 자료형에 상관없이 변수는 무조건 "?"이다.
            
            //4. DML(insert/update/delete) : res는 처리된 행의 수를 반환합니다. 한번의 삽입은 무조건 1줄만 수행되므로 삽입이 성공했다면 res는 반드시 1, 만약에 res가 0이라면 삽입연산이 제대로 수행되지 않은 것이다.
            res = pstmt.executeUpdate();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            try {
                //닫기(열린역순)
                if(pstmt != null) pstmt.close(); //2
                if(conn  != null) conn.close();  //1
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        return res;
    }
cs

위에서 보시는 바와 같이 기본적인 틀은 세개의 메서드가 모두 같습니다. 차이점은 아래에 정리하겠습니다.

  • 각 명령마다 실행되는 SQL문이 다름. 이는 메서드 마다 직접 작성해주어야 합니다.
  • prepareStatement의 특성상 변수가 ?로 작성되어 미완성된 SQL문을 전송하고, 이후에 파라미터값을 전송하게 되는데, 위의 각 메소드의 특징을 설명한 부분을 보시면 메서드마다 포장하는 데이터의 종류 혹은 메서드의 매개변수가 조금씩 상이한 것을 알 수 있습니다. 즉, 메서드마다 3의 파라미터 변수 설정이 다릅니다.
  • insert ->  insert into sungtb values(seq_sungtb_idx.nextVal, ?, ?, ?, ?)
  • delete -> delete from sungtb where idx = ?
  • update -> update sungtb set name=?, kor = ?, eng = ?, mat = ? where idx=?

[정리] - 버튼을 설계하는 기법은 생략

  1. insert메소드는 추가할 데이터를 포장하고, 명령을 실행한 뒤, current_pos의 값을 가장 마지막 행을 가리키도록 갱신해주며, 데이터를 새로 불러서 다시 출력합니다.
  2. update메소드는 수정할 데이터를 포장하고, 명령을 실행한 뒤, 데이터를 새로 불러서 다시 출력합니다. 
  3. delete메소드는 행을 삭제하고, 삭제 이후 남아있는 데이터가 없는지, 방금 삭제한 데이터가 마지막 행이었는지를 고려하여 조건을 설정해주어야 합니다.

'데이터베이스' 카테고리의 다른 글

SQLD_데이터 모델링의 이해  (0) 2022.09.20
Tomcat다운로드&환경설정_HTML_국비_DAY40  (0) 2022.04.26
DB 모듈화  (0) 2022.04.22
JDBC의 사용법  (0) 2022.04.21
Join  (0) 2022.04.20