2018-12-17 수업 내용 정리

자바의 직렬화

  • 자바 기본(primitive) 타입과 java.io.Serializable 인터페이스를 상속받은 객체는 직렬화 할 수 있는 기본 조건을 가진다.
  • 직렬화란?
    자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기

  • ObjectInputStream, ObjectOutputStream
    객체 스트림 : 객체 안에 저장되어 있는 내용을 직접 입출력할 수 있도록 해준다

  • hashMap.keySet()
    hashMap에 저장된 모든 키 반환

  • FileInputStream, FileOutputStream

    바이트 단위의 입출력을 받는 클래스
    출발 지점과 도착 지점을 연결하는 통로 생성
    file로 입력 스트림 생성

  • File.exists()
    해당 이름의 파일이나 디렉토리가 있는지 여부를 검사

  • File.mkdir()
    폴더 생성

동기화

  • 작업이 진행되는 동안 락이 걸리는 것

    1
    2
    3
    public synchronized void openDoor(String name) {

    }
  • vector는 동기화가 되어 있고, arrayList는 동기화가 되어있지 않다.

  • arrayList가 vector보다 성능이 좋은 이유는, 동기화가 되어있지 않기 때문이다.

  • 쓰레드 : 순서를 정의할 수 없음

    • 프로세스 : 동작하고 있는 프로그램
      보통 한 개의 프로세스는 한 가지의 일을 한다.
    • 쓰레드를 이용하면 한 프로세스 내에서 두 가지 또는 그 이상의 일을 동시에 할 수 있게 된다.
    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
    //동기화
    //한강둔치 화장실(공유자원) : 여러명 10명 (각각의 Thread 10개)
    //한강둔치 비빕밥 축제

    //Multi Thread 환경에 [공유자원]
    //해결 방법 : lock

    //함수 단위 LocK (동기화 보장)

    class Wroom{
    public synchronized void openDoor(String name) {
    //public void openDoor(String name) {
    System.out.println(name + "님 화장실 입장 ^^");
    for(int i = 0; i < 50 ;i++) {
    System.out.println(name + "사용 : "+ i);
    if(i == 1000) {
    System.out.println(name + "님 끙 !!");
    }
    }
    System.out.println(name + "시원하시죠 ....");
    }
    }

    class Users extends Thread{
    private Wroom wr;
    private String who;

    public Users(String name , Wroom wr) {
    this.who = name;
    this.wr = wr;
    }

    @Override
    public void run() {
    wr.openDoor(this.who);
    }
    }

    public class Ex09_sync_Thread {

    public static void main(String[] args) {
    //한강둔치
    Wroom w = new Wroom();

    //사람들
    Users kim = new Users("김씨", w);
    Users Lee = new Users("이씨", w);
    Users Park = new Users("박씨", w);

    kim.start();
    Lee.start();
    Park.start();

    }

    }

PL/SQL

오토커밋이 되지 않는다.

end구문에 반드시 세미콜론!

1
2
3
BEGIN
DBMS_OUTPUT.PUT_LINE('HELLO WORLD');
END;

변수 선언

1
2
3
4
5
6
7
8
9
DECLARE --선언
vno number(4);
vname varchar2(20);
BEGIN
vno := 100; -- 할당 > String s; s = "홍길동"
vname := 'kglim';
DBMS_OUTPUT.PUT_LINE(vno); --화면 출력
DBMS_OUTPUT.PUT_LINE(vname || '입니다');
END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DECLARE
vno number(4);
vname varchar2(20);
BEGIN
select empno ,ename
into vno , vname
-- pl-sql 사용하는 구분 (into) . 실행결과 변수에 담기
-- 오라클엔 존재하지 않는다.
-- VNO에 EMPNO를
-- VNAME에 ENAME을 담는다
from emp
where empno=&empno;
-- & 자바 scanner 역할 (입력값 받기)

DBMS_OUTPUT.PUT_LINE('변수값 : ' || vno || '/' || vname);
END;

실행하면 INPUT 창이 뜬다.

제어문

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
--pl-sql 제어문
DECLARE
vempno emp.empno%TYPE;
vename emp.ename%TYPE;
vdeptno emp.deptno%TYPE;
vname varchar2(20) := null;
BEGIN
select empno , ename , deptno
into vempno , vename , vdeptno
from emp
where empno=7788;
--제어문 if(조건문){실행문}
IF(vdeptno = 10) THEN vname := 'ACC'; -- if(vdeptno==10) { vname = "ACC"} else if(){}
ELSIF(vdeptno=20) THEN vname := 'IT';
ELSIF(vdeptno=30) THEN vname := 'SALES';
END IF;
DBMS_OUTPUT.PUT_LINE('당신의 직종은 : ' || vname);
END;

--IF() THEN 실행문
--ELSIF() THEN 실행문
--ELSE 실행문
--사번이 7788번인 사원의 사번 , 이름 , 급여를 변수에 담고
--변수에 담긴 급여가 2000 이상이면 '당신의 급여는 BIG' 출력하고
--그렇지 않으면(ELSE) '당신의 급여는 SMALL' 이라고 출력하세요

DECLARE
vempno emp.empno%TYPE;
vename emp.ename%TYPE;
vsal emp.sal%TYPE;
BEGIN
select empno , ename , sal
into vempno , vename , vsal
from emp
where empno=7788;
--제어문 if(조건문){실행문}
IF(vsal > 2000) THEN
DBMS_OUTPUT.PUT_LINE('당신의 급여는 BIG ' || vsal);
ELSE
DBMS_OUTPUT.PUT_LINE('당신의 급여는 SMALL ' || vsal);
END IF;
END;

-------------------------------------------------------------------------------
--CASE
DECLARE
vempno emp.empno%TYPE;
vename emp.ename%TYPE;
vdeptno emp.deptno%TYPE;
v_name varchar2(20);
BEGIN
select empno, ename , deptno
into vempno, vename , vdeptno
from emp
where empno=7788;

-- v_name := CASE vdeptno
-- WHEN 10 THEN 'AA'
-- WHEN 20 THEN 'BB'
-- WHEN 30 THEN 'CC'
-- WHEN 40 THEN 'DD'
-- END;

v_name := CASE
WHEN vdeptno=10 THEN 'AA'
WHEN vdeptno in(20,30) THEN 'BB'
WHEN vdeptno=40 THEN 'CC'
ELSE 'NOT'
END;
DBMS_OUTPUT.PUT_LINE('당신의 부서명:' || v_name);
END;
--------------------------------------------------------------------------------
--pl-sql (반복문)
--Basic loop
/*
LOOP
문자;
EXIT WHEN (조건식)
END LOOP
*/
DECLARE
n number :=0;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE('n value : ' || n);
n := n + 1;
EXIT WHEN n > 5;
END LOOP;
END;

/*
WHILE(n < 6)
LOOP
실행문;
END LOOP
*/
DECLARE
num number := 0;
BEGIN
WHILE(num < 6)
LOOP
DBMS_OUTPUT.PUT_LINE('num 값 : ' || num);
num := num +1;
END LOOP;
END;

--for
--java for(int i = 0 ; i < 10 ; i++) {}
BEGIN
FOR i IN 0..10 LOOP
DBMS_OUTPUT.PUT_LINE(i);
END LOOP;
END;
1
2
3
4
5
6
7
8
9
10
11
12
--11g 이전 (continue (x))
--11g (continue 추가)
DECLARE
total number := 0;
BEGIN
FOR i IN 1..100 LOOP
DBMS_OUTPUT.PUT_LINE('변수 : ' || i);
CONTINUE WHEN i > 5; --skip
total := total + i; -- 1 , 2 , 3 , 4, 5
END LOOP;
DBMS_OUTPUT.PUT_LINE('합계 : ' || total);
END;

예외처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  --예외처리
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(v_name || '는 자료가 없습니다');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE(v_name || '는 동명 이인입니다');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('기타 에러가 발생했습니다');
END;
/*
질의는 하나의 행만 RETURN 해야 합니다. PL/SQL 블록 내의 SELECT 문장은 다음 규칙을
적용하는 Embedded SQL 의 ANSI 범주에 속합니다. 질의의 결과는 하나의 행만을 RETURN 해
야 하고 하나의 행 이상 또는 행이 없는 것은 에러를 생성합니다. PL/SQL 은
NO_DATA_FOUND 와 TOO_MANY_ROWS 를 예외로 블록의 예외 섹션에서 추적할 수 있는 표준 예
외를 조성하여 처리 합니다.
*/
1
2
3
4
-- 변수 제어하기(타입)
-- 1.1 타입 : v_empno number(10)
-- 1.2 타입 : v_empno emp.empno%TYPE (emp 테이블에 있는 empno 컬럼의 타입 사용)
-- 1.3 타입 : v_row emp%ROWTYPE (v_row 변수는 emp 테이블 모든 컬럼 타입 정보, 배열)

시퀀스

1
2
3
4
5
6
7
8
9
10
create sequence empno_seq
increment by 1
-- 시퀀스 증감 숫자
start with 8000
maxvalue 9999
nocycle
-- 디폴트 값으로 최대나 최솟값에 도달하면 생성 중지
-- cycle이면 다시 최솟값이나 최대값에서 시작
nocache;
-- 디폴트로 메모리에 시퀀스 값을 미리 할당해 놓지 않으며 디폴트 값은 20
  • SQL%ROWCOUNT는 마지막에 업데이트 된 행을 뜻한다.

커서

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
DECLARE
vempno emp.empno%TYPE;
vename emp.ename%TYPE;
vsal emp.sal%TYPE;
CURSOR c1 IS select empno,ename,sal from emp where deptno=30;
BEGIN
OPEN c1; --커서가 가지고 있는 문장 실행
LOOP
--Memory
/*
7499 ALLEN 1600
7521 WARD 1250
7654 MARTIN 1250
7698 BLAKE 2850
7844 TURNER 1500
7900 JAMES 950
*/
FETCH c1 INTO vempno , vename, vsal;
EXIT WHEN c1%NOTFOUND; --더이상 row 가 없으면 탈출
DBMS_OUTPUT.PUT_LINE(vempno || '-' || vename || '-'|| vsal);
END LOOP;
CLOSE c1;
END;
-------------------------------------------------------
--위 표현을 좀 더 간단하게
--java (for(emp e : emplist){}
DECLARE
CURSOR emp_curr IS select empno ,ename from emp;
BEGIN

FOR emp_record IN emp_curr --row 단위로 emp_record변수 할당
LOOP
EXIT WHEN emp_curr%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_record.empno || '-' || emp_record.ename);
END LOOP;

CLOSE emp_curr;
END;

--------------------------------------------------------------------------------
DECLARE
vemp emp%ROWTYPE; --Type 정의
CURSOR emp_curr IS select empno ,ename from emp;
BEGIN
FOR vemp IN emp_curr --row 단위로 emp_record변수 할당
LOOP
EXIT WHEN emp_curr%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(vemp.empno || '-' || vemp.ename);
END LOOP;
CLOSE emp_curr;
END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DECLARE
vempno emp.empno%TYPE;
vename emp.ename%TYPE;
vsal emp.sal%TYPE;
CURSOR c1 IS select empno,ename,sal from emp where deptno=30;
BEGIN
OPEN c1; --커서가 가지고 있는 문장 실행
LOOP
--Memory
/*
7499 ALLEN 1600
7521 WARD 1250
7654 MARTIN 1250
7698 BLAKE 2850
7844 TURNER 1500
7900 JAMES 950
*/
FETCH c1 INTO vempno , vename, vsal;
EXIT WHEN c1%NOTFOUND; --더이상 row 가 없으면 탈출
DBMS_OUTPUT.PUT_LINE(vempno || '-' || vename || '-'|| vsal);
END LOOP;
CLOSE c1;
END;
1
2
3
4
5
6
7
8
9
10
11
12
13
DECLARE
CURSOR emp_curr IS select empno ,ename from emp;
BEGIN

FOR emp_record IN emp_curr --row 단위로 emp_record변수 할당
-- open과 fetch 생략
LOOP
EXIT WHEN emp_curr%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_record.empno || '-' || emp_record.ename);
END LOOP;

CLOSE emp_curr;
END;
1
2
3
4
5
6
7
8
9
10
11
DECLARE
vemp emp%ROWTYPE; --Type 정의
CURSOR emp_curr IS select empno ,ename from emp;
BEGIN
FOR vemp IN emp_curr --row 단위로 emp_record변수 할당
LOOP
EXIT WHEN emp_curr%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(vemp.empno || '-' || vemp.ename);
END LOOP;
CLOSE emp_curr;
END;

커서의 타입

1
2
3
4
5
6
7
8
9
10
11
12
13
create or replace procedure usp_emplist
(
p_sal IN number,
p_cursor OUT SYS_REFCURSOR
-- app 에서 값을 사용하기 위해서(Multi row)
)
is
BEGIN
OPEN p_cursor
FOR
select empno ,ename , sal from emp
where sal > p_sal;
END;

프로시저에서 한 건 이상의 결과 값은 무조건 커서를 써야 한다.

커서를 아웃풋으로 잡고, 커서의 자료형을 SYS_REFCURSOR로 한다.

트랜젝션 및 예외 처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DECLARE
v_ename emp.ename%TYPE := '&p_ename';
v_err_code NUMBER;
v_err_msg VARCHAR2(255);
BEGIN
DELETE emp WHERE ename = v_ename;
IF SQL%NOTFOUND THEN
-- 만약 해당 데이터가 없으면
RAISE_APPLICATION_ERROR(-20001,'my no data found');
-- 에러 번호, 메시지
--사용자 정의 예외 만들기
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
v_err_code := SQLCODE;
-- SQLCODE : -20001
v_err_msg := SQLERRM;
-- SQLERRM : my no data found
DBMS_OUTPUT.PUT_LINE('에러 번호 : ' || TO_CHAR(v_err_code));
DBMS_OUTPUT.PUT_LINE('에러 내용 : ' || v_err_msg);
END;

프로시저

  • 생성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    create or replace procedure usp_emplist
    is
    BEGIN
    update emp
    set job = 'TTT'
    where deptno=30;
    commit
    -- 만약 commit을 하지 않으면 rollback 된다!
    END;
  • 함수는 select 구문, 프로시저는 단독 사용 가능

  • 실행

    1
    execute usp_emplist;

서버와 db가 따로 구축되었을 때 update문을 실행하면 update 쿼리를 빼갈 수 있다.

반면 프로시저를 사용하면 콜하는 프로시저만 빼갈 수밖에 없다.

프로시저가 db 안에 있기 때문

프로시저의 장점은 네트워크 트래픽 감소, 보안 강화

파라미터 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
--parameter  사용가능
--종류 : INPUT , OUTPUT
create or replace procedure usp_update_emp
(vempno emp.empno%TYPE)
is
BEGIN
update emp
set sal = 0
where empno = vempno;
END;
--실행방법
exec usp_update_emp(7788);
-- 단축 표현법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
create or replace procedure usp_getemplist
(vempno emp.empno%TYPE)
is
--내부에서 사용하는 변수
vname emp.ename%TYPE;
vsal emp.sal%TYPE;
BEGIN
select ename, sal
into vname , vsal
from emp
where empno=vempno;

DBMS_OUTPUT.put_line('이름은 : ' || vname);
DBMS_OUTPUT.put_line('급여는 : ' || vsal);
END;
input과 output
  • input paramter : 사용시 반드시 입력 (default)

  • output parmater

    • 사용시 입력값을 받지 않는다.
    • 결과를 담고 있어 받을 변수가 필요함
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    create or replace procedure app_get_emplist
    (
    vempno IN emp.empno%TYPE,
    -- 강제
    vename OUT emp.ename%TYPE,
    vsal OUT emp.sal%TYPE
    -- 입력값 받지 않음
    )
    is
    BEGIN
    select ename, sal
    into vename , vsal
    from emp
    where empno=vempno;
    END;

    실행

    1
    2
    3
    4
    5
    6
    7
    8
    9
    DECLARE
    out_ename emp.ename%TYPE;
    out_sal emp.sal%TYPE;
    BEGIN
    app_get_emplist(7902,out_ename,out_sal);
    -- 보내는 변수는 프로시저의 out 파라미터
    -- 리턴 값을 받아낼 것들 자료형 맞춰서 변수 보냄
    DBMS_OUTPUT.put_line('출력값 : ' || out_ename || '-' || out_sal);
    END;

사용자 함수

  • 프로시저와 다른 점 : return 타입
1
2
3
4
5
6
7
8
9
10
11
12
13
create or replace function f_max_sal
(s_deptno emp.deptno%TYPE)
return number
-- public int f_max_sal(int deptno) { int max_sal = 0; return 10}
is
max_sal emp.sal%TYPE;
BEGIN
select max(sal)
into max_sal
from emp
where deptno = s_deptno;
return max_sal;
END;
  • 리턴에 대한 타입

  • 정말 리턴되는 것

  • 즉 리턴이 두 개 명기된다.

  • 사용법

    1
    2
    select * from emp where sal = f_max_sal(10);
    select max(sal) , f_max_sal(30) from emp;