티스토리 툴바


서로다른 캐릭터셋을 가진 DB간에 DBLINK 를 이용할 경우 한글등이 깨지는 것을 어떻게 처리할 것인가?

URL_RAW Package 를 이용해서 처리해 보자.
URL_RAW Package 는 Oralcle 8 이상에서 제공 된다고 한다.

--------------------------------------------------------------------------------
1. 환경
    1-1. ORACLE 8.1.7  : US7ASCII
    1-2. ORACLE 10.2.0 : UTF8

2. 1-2 에서 DB LINK 를 통해서 1-1 의 테이블을 조회할 경우
--------------------------------------------------------------------------------

1. 1-1. DB 에 VIEW 생성

CREATE VIEW VIEW_TORAW AS
SELECT COL1, COL2
     , UTL_RAW.CAST_TO_RAW(KOR_COL1) AS RAW_KOR_COL1
     , UTL_RAW.CAST_TO_RAW(KOR_COL2) AS RAW_KOR_COL2
  FROM TEST
;

2. 1-2. DB 에 VIEW 생성
CREATE VIEW VIEW_TOVARCHAR AS
SELECT COL1, COL2
     , UTL_RAW.CAST_TO_VARCHAR2(RAW_KOR_COL1) AS KOR_COL1
     , UTL_RAW.CAST_TO_VARCHAR2(RAW_KOR_COL2) AS KOR_COL2
  FROM VIEW_TORAW@DBLINKNM
;

위와 같이 UTL_RAW 패키지를 이용해서 변환해줄경우 한글처리가 가능하다.
물론 2. 번의 VIEW 대신 바로 SELECT 만 이용해도 가능하다.

DBMS_RANDOM package

Oracle 2008/07/29 14:18

DBMS_RANDOM package

The DBMS_RANDOM package will generate random data in character, numeric or alphanumeric formats. The size and the range from which to pickup the random values can also be specified. This package is created by the script dbmsrand.sql available in the <ORACLE_HOME>/rdbms/admin directory.

The following functions present in the package can be used to serve the purpose of generating random numbers and strings. RANDOM - generate random numbers.

VALUE - generate random numbers from the range provided. The range will be taken as 0-1 if none is provided.

STRING - generate strings in upper case, lower case or alphanumeric format.

  • The first parameter takes the string type to be generated, the following values can be provided in upper or lower case.
  • U - Upper case
  • L - Lower case
  • A - Alphanumeric
  • X - Alphanumeric with upper case alphabets.
  • P - Printable characters only.

    Providing any other character will return the output in upper case only.

    The size of the string should also be provided as the second parameter.

Oracle documentation says that it is necessary to initialize the package before using the random number generator. Oracle by default initializes the package with the seed value as the current user name, current time down to the second and the current session id.

INITIALIZE - Initialize the package to proceed with the number generation.

Provide a number (seed) as input to the routine.

SEED - Used to change the seed value. It is used in the internal algorithm to generate values. Setting this will

generate the random numbers in an order that will be similar in multiple sessions. Refer to the example below.

TERMINATE - Close the process of random number generation.

Examples:

Below are some examples of using the package.

E.g.: Generating a random number (positive or negative)

SQL> select dbms_random.random from dual;

       RANDOM
_____________
   1393936551

E.g.: Generating a random number between 0 and 1.

SQL> select dbms_random.value from dual;

        VALUE
_____________
            1

E.g.: Generating a random number from a range, between 1 to 1000.

SQL> select dbms_random.value(1,1000) num from dual;

          NUM
_____________
          611

E.g.: Generating a 12 digit random number.

SQL> select dbms_random.value(100000000000, 999999999999) num from dual;

          NUM
_____________
 175055628780

E.g.: Generating an upper case string of 20 characters

SQL> select dbms_random.string('U', 20) str from dual;

STR
_______________________
VUOQOSTLHCKIPIADIZTD

E.g.: Generating a lower case string of 20 characters

SQL> select dbms_random.string('L', 20) str from dual;

STR
____________________
xpoovuspmehvcptdtzcz

E.g.: Generating an alphanumeric string of 20 characters. There is a bug in Oracle 8i that results in special (non-alphanumeric) characters such as ']' in the string. This is resolved in Oracle 9i.

SQL> select dbms_random.string('A', 20) str from dual;

STR
__________________
sTjERojjL^OlTaIc]PLB

E.g.: Generating an upper case alphanumeric string of 20 characters

SQL> select dbms_random.string('X', 20) str from dual;

STR
________________________
SQ3E3B3NRBIP:GOGAKSC

E.g.: Generating a string of printable 20 characters. This will output a string of all characters that could possibly be printed.

SQL> select dbms_random.string('P', 20) str from dual;

STR
___________________
*Yw>IKzsj\uI8K[IQPag

E.g.: Example for calling the dbms_random package and setting the seed for generating the same set of random numbers in different sessions. Please note that the same random numbers are generated in different sessions. Though I have found this to work on most accounts, in some cases, the first number generated was different in different sessions and the remaining were same. I recommend not using this option in any of production code until it is properly document by Oracle.

jaJA>declare
  2     l_num    number;
  3  begin
  4    l_num := dbms_random.random;
  5    dbms_output.put_line(l_num);
  6    dbms_random.seed('amar testing 67890');
  7    l_num := dbms_random.random;
  8    dbms_output.put_line(l_num);
  9  end;
 10  /
483791552
478774329

PL/SQL procedure successfully completed.

GROUP BY ROLLUP, CUBE

Oracle 2008/07/16 12:29

1. ROLLUP : N+1  개를 그룹핑
2. CUBE    : 2의 N 제곱개를 그룹핑

-----------------------------------------------------------------------------------
1. GROUP BY ROLLUP(A, B, C)
   1-1. A, B, C
   1-2. A, B
   1-3. A
   1-4. 전체
   로 그룹핑을 한다.

* 아래 두개의 차이를 확인해보자.

WITH T_TABLE AS
(
 SELECT '0001' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '01' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 30 USE, 3000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALl
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL
)
SELECT
    ITEM
  , SUBITEM
  , SUM(USE)
  , SUM(AMOUNT)
  FROM T_TABLE
 GROUP BY ROLLUP(ITEM, SUBITEM)
;

WITH T_TABLE AS
(
 SELECT '0001' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '01' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 30 USE, 3000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL
)
SELECT
    ITEM
  , SUBITEM
  , SUM(USE)
  , SUM(AMOUNT)
  FROM T_TABLE
 GROUP BY ROLLUP((ITEM, SUBITEM))
;

-----------------------------------------------------------------------------------

WITH T_TABLE AS
(
 SELECT '0001' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '01' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 30 USE, 3000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL
)
SELECT
    GROUPING_ID('AVG')
  , GROUPING_ID(ITEM)
  , ITEM
  , GROUPING_ID(SUBITEM)
  , SUBITEM
  , SUM(USE)
  , SUM(AMOUNT)
  FROM T_TABLE
 GROUP BY ROLLUP('AVG', ITEM, SUBITEM)
;

WITH T_TABLE AS
(
 SELECT '0001' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '01' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '02' SUBITEM, 30 USE, 3000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0001' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '01' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '02' SUBITEM, 20 USE, 2000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL UNION ALL
 SELECT '0002' ITEM, '03' SUBITEM, 10 USE, 1000 AMOUNT FROM DUAL
)
SELECT
    DECODE(
     ITEM, NULL, DECODE(
         GROUPING_ID('AVG'), 1, 'AVG', 'TOTAL'
        ), ITEM
    ) ITEM
  , DECODE(
     GROUPING_ID(ITEM), 1, '', DECODE(
              GROUPING_ID(SUBITEM), 1, 'SUBTOTAL', SUBITEM
             )
    ) SUBITEM
  , DECODE(
     GROUPING_ID('AVG'), 1, AVG(USE),
          SUM(USE)
    ) USE
  , DECODE(
     GROUPING_ID('AVG'), 1, AVG(AMOUNT),
          SUM(AMOUNT)
    ) AMOUNT
  FROM T_TABLE
 GROUP BY ROLLUP('AVG', ITEM, SUBITEM)
;

-----------------------------------------------------------------------------------

2. GROUP BY CUBE(A, B, C)
   2-1. A, B, C
   2-2. A, B
   2-3. B, C
   2-4, A, C
   2-5, A
   2-6. B
   2-7. C
   2-8. 전체
   로 그룹핑을 한다.


Visio Reverse Engineer

Oracle 2008/04/29 17:59
VISIO 에서 Oracle DataBase 내의 테이블 Reverse Engineer 하는 방법.

1. ODBC 설치(Window XP 기준)
   1-1. 제어판 - 관리도구 - 데이터원본(ODBC)
   1-2. 사용자 DSN 탭 - 추가
   1-3. 데이터원본을 설정할 드라이버 - 로컬에 설치된 Oracle Client
   1-4. Microsoft ODBC for Oracle Setup
         - 데이터 원본이름      : DATABASE 명(아무거나 넣어도 된다)
         - 설명                      : 설명
         - TNS Service Name : 해당 TNS NAME
         - 사용자 이름            : Oracle 에 접속할 수 있는 유저 ID

2. Visio 작성(Microsoft Visio 2003 기준)
   2-1. 파일 - 새로만들기 - 데이타베이스 - 데이타베이스 모델 다이어그램
   2-2. 데이타베이스 - 리버스 엔지니어링
   2-3. 리버스 엔지니어링 마법사
         - 설치된 Visio 드라이버 : Oracle Server
         - 데이터원본                : 1. ODBC 설치에서 생성된 데이터 원본이름
         - 다음 클릭시 User/Password 입력
   2-4. Object Type 선택
          - 추출할 테이블, 뷰 ...


이상.

NSL_CHARACTERSET

Oracle 2007/11/20 16:29
발췌 : http://blog.naver.com/kkhigh5/30023536431

현재 한글을 지원하는 캐릭터셋으로는 다음 네 가지가 있다. 오직 이 네 가지이다.
각각의 특색이 다르므로 유의해야 한다.

1. KO16KSC5601
2. KO16MSWIN949
3. UTF8
4. AL32UTF8

1. KO16KSC5601

이름에서 알 수 있는 바와 같이 이 캐릭터셋은 한글 완성형 코드와 일치한다.
완성형은 일반적으로 많이 사용되는 2350자의 한글을 25*94 매트릭스에 배열한 문자셋이며, 4888자의 한자와 히라카나, 카타카나, 그리고 영문 및 각종 기호들을 포함하고 있다.
유닉스 환경에서는 LANG=ko로 하여 DBCA(Database Configuration Assistant)를 실행할 경우, 자동으로 캐릭터셋을 KO16KSC5601로 지정한다. 물론 변경할 수도 있다.

"KO16KSC5601 캐릭터셋을 사용하기 전에 그 특성을 제대로 알고 사용하자"

 [데이타 예제]

  아햏햏
  모두에게 먄하게 되었소. 솔믜가 예약했던 커피숖이 배신을 때리는 바람에 그만 낙동강
  오리알이 되었지요. 정말 먄하오.
  똠방각하

불행하게도 여러분의 KO16KSC5601 데이터베이스는 이 글을 제대로 저장할 수 없다.
이 글을 저장한 후 다시 읽으려고 하면 다음과 같은 결과를 보게 될 뿐이다.

  [결과]

  아? ?
  모두에게 ?하게 되었소. 솔?가 예약했던 커피?이 배신을 때리는 바람에 그만 낙동강
  오리알이 되었지요. 정말 ?하오.
  ?방각하

"캐릭터셋 지정 전에 반드시 사용할 시스템이 어느 정도 범위의 한글 지원을 원하는가를 확실히 검사할 필요가 있다"

2. KO16MSWIN949

Windows-949 캐릭터셋은 마이크로소프트사의 Windows Codepage 949번,
즉 한글 코드 페이지를 따른 코드셋이다.
이는 완성형(KO16KSC5601)을 그대로 포함하고 있으며, 추가로 현대 한글 조합으로 표현할 수 있는 모든 가짓수에 해당하는 8822자의 한글을 추가해 포함하고 있다.
그러니까 "Windows-949 캐릭터셋은 KSC5601의 수퍼셋(Superset)"이 되며,
따라서 "KO16MSWIN949 또한 KO16KSC5601의 수퍼셋"이 된다.

"다른 운영 체제에서도 사용할 수 있다!"
운영 체제가 Windows 949 코드 페이지를 지원하지 않는다고 해서, KO16MSWIN949 캐릭터셋을 가진 데이터베이스 인스턴스를 생성할 수 없다는 것은 아니다.
데이터베이스 캐릭터셋과 운영체제의 캐릭터셋은 전혀 별개라고 인식해야 한다.
비록 Windows-949는 특정 업체의 문자셋이기는 하지만,
이를 기반으로 한 KO16MSWIN949 캐릭터셋은 한글 2350자의 한계를 가진 KO16KSC5601의 대안으로 용이하게 이용될 수 있다. 기억하자.
Unix에서든 Linux에서든, KO16MSWIN949 캐릭터셋을 가진 데이터베이스 인스턴스를 생성할 수 있다.

3. UTF8/AL32UTF8

UTF8은 유니코드를 구현한 캐릭터셋 중에 가변길이 인코딩 방식을 택하고 있는 캐릭터셋이다. 자세한 인코딩 방식은 여기에서 논할 필요가 없지만, 가변 길이를 위해 일종의 플래그 비트를 각 바이트마다
포함시켜야 하다보니, 한 글자를 표한하는데 필요한 바이트의 길이가 최대 3바이트(AL32UTF8의 경우 6바이트)까지 늘어날 수 있다.

유니코드는 잘 알려진 바와 같이 현대 한글 11172자를 모두 가나다 순으로 잘 정렬된 상태로 포함하고 있다.
그래도 한글 한 자가 3바이트의 물리적 공간을 차지하므로, 오로지 모든 한글을 지원한다는 이유만으로 사용하는 것은 곤란하다. 하지만, 한글 이외에도 다른 언어들을 함께 데이터베이스에 저장해야 한다면 다른 선택의 여지가 없는 유일한 선택이 된다.

4. National Characterset

네셔널 캐릭터셋은 유니코드를 지원하지 않는 캐릭터셋을 가진 데이터베이스에서 유니코드를 지원하기 위해 부가적으로 설정할 수 있는 캐릭터셋이다. 즉, 하나의 데이터베이스 인스턴스는 "캐릭터셋"과 "네셔널 캐릭터셋"을 가진다. 처음 시스템 구축 당시와는 달리, 한글 이외의 다른 언어를 급히 저장해야 할 필요성이 있는 경우 네셔널 캐릭터셋을 적절히 활용할 수 있다.

네셔널 캐릭터셋을 가능한 캐릭터셋은 단 두 가지이다. UTF8과 AL16UTF16(기본값).
네셔널 캐릭터셋을 사용하기 위해서는 특정 타입으로 테이블의 컬럼 또는 PL/SQL 변수를 선언해야 한다. CHAR와 VARCHAR2,CLOB에 대응되는 네셔널 캐릭터셋 기반의 타입으로는 NCHAR, NVARCHAR2,NCLOB이 있다.

즉, KO16MSWIN949 데이터베이스에서 다음과 같이 테이블을 생성할 경우,

CREATE TABLE test_table
( varchar_value VARCHAR2(2000),
nvarchar_value NVARCHAR2(2000)
);
"varchar_value" 컬럼에는 KO16MSWIN949에 속하는 글자들만 저장할 수 있는 반면, nvarchar_value 컬럼에는 유니코드에 속한 모든 글자들을 저장할 수 있다. 약간의 부가적인 코드가 필요할 뿐, 실제 프로그래밍 방식은 거의 같다.

5. 캐릭터셋 선택의 원칙

많은 원칙이 필요없다. 다음 몇가지만 기억하자.

한글 지원을 위해서는 반드시 위의 네 가지 캐릭터셋 중에 하나를 선택해야 한다
한국에서만 사용하는 시스템이라면 KO16MSWIN949를 선택한다
한국어 뿐 아니라 중국어, 일본어, 러시아어 등 다양한 언어로 된 데이터를 저장해야 한다면 UTF8, AL32UTF8을 선택한다. 인코딩 변환으로 한국어 기반의 캐릭터셋에 비해 속도의 저하가 있다고 알려져 있다.

대부분이 한글이며, 일부 외국어가 필요하다면, 한국어 기반의 캐릭터셋(KO16MSWIN949)을 사용하되, National Characterset을 이용한 컬럼에 외국어를 저장한다.

6.NLS_LANG 변수 값 설정

이에 따라, Windows 운영체제에서 한국어 환경을 사용하는 사용자들은 다음과 같이 NLS_LANG 값을 설정할 수 있다.
KOREAN_KOREA.KO16MSWIN949

그리고, 유닉스 운영체제에서 한국어를 입출력한다면 다음과 같이 NLS_LANG을 설정할 수 있다.
KOREAN_KOREA.KO16KSC5601

데이터베이스가 UTF8이든 KO16MSWIN949이든 상관없이 한글을 지원하는 데이터베이스와 통신한다면 반드시 위와 같이 NLS_LANG값을 설정해야 한다.

7.한글을 지원하는 캐릭터셋 비교 테이블

                    KO16KSC5601     KO16MSWIN949       UTF8           AL32UTF8
--------------------------------------------------------------------------------------------------- 한글지원        2350자               KO16KSC5601 +       11172자      11172자
                                               확장 8822자(총 11172자)
--------------------------------------------------------------------------------------------------- 지원버젼        7.x                          8.0.6 이상              8.0 이후    9i Release 1 이상
---------------------------------------------------------------------------------------------------Database
Characterset    가능                     가능                          가능            가능
으로 설정
가능 여부
---------------------------------------------------------------------------------------------------National
Characterset    불가능                 불가능                        가능            불가능
으로 설정   
가능 여부
---------------------------------------------------------------------------------------------------

ORA-29275

Error 2007/11/20 16:12
ORA-29275 : 부분 다중 바이트 문자

단순 SQL 문을 만들어서 조회를 하는데도 위와 같은 오류가 난다면,
1. 서버 ORACLE 환경
2. 로컬 윈도우의 오라클환경(CLIENT)
위 두개의 CHARACTERSET 을 확인해보자.

1. 서버 ORACLE 환경
   - SELECT * FROM SYS.PROPS$
       WHERE NAME = 'NLS_CHARACTERSET'
     <결과>
     NAME                           VALUE$               COMMENT$
     ---------------------------------------------------------
     NLS_CHARACTERSET     KO16KSC5601       Character set

2. 로컬 윈도우의 오라클환경(CLIENT)
    - 레지스트리 편집기에서 "NLS_LANG" 을 찾아보자.
      나 같은 경우는 찾기를 했더니 요기에 있더라
      HKEY_LOCLA_MACHINE\SOFTWARE\ORACLE\KEY_OraClient10G_home1
      NLS_LANG 값이 KOREAN_KOREA.KO16MSWIN949 이거로 되어있다.

만약 위와 같이 1/2의 CHARSET 이 다르다면 ORA-29275 에러를 만나게 되리라. ^^

그렇다면 어떻게 한다.
잘 쓰고 있는 서버에 CHARSET  을 변경한다는건 너무 무모한 짓이고
로컬컴터의 레지스트리를 바꾸어주자. ^^
서버 ORACLE 환경의 CHARSET 으로 ...
NLS_LANG 값을 KOREAN_KOREA.KO16KSC5601 로 바꾸자.

다시 한번 SQL 을 날려보라~~
잘 될것이다.




[Network]MAC Address

용어 2007/11/14 02:50
[MAC - Media Access Control]
근거리통신망에서 MAC 주소는 데이터 링크 계층의 MAC 계층에 의해 사용되는
주소로서 네트웍카드의 48비트 하드웨어 주소를 말하며, 
이더넷 주소, 또는 토클링 주소와 동일하다.

네트워크에 연결되는 모든 장비는 각자 유일한 주소를 가지게 되는데 이 주소는 48bits의
크기를 가진다. 실제로 이 주소를 라우터나 스위치를 포함 랜카드에도 부여가 되는데
이 주소는 각 장비의 ROM 에 영구 저장된다.
이 주소는 컴퓨터를 켜면 이 ROM에 있는 주소가 RAM에 올라가서 통신할때 사용되게 된다.

IEEE 라는 기관에서 MAC 주소를 관리하고, 이 48bits는 제조자 코드+일련번호로 구성된다.
제조자코드(Organizational Unique Identifier)는 상위 24bits
일련번호(Host Identifier)는 하위 24bits를 나타낸다.

주소 크기는 48bit 이며, 16진수로 표기된다
8bit 단위로 - 또는 : 으로 구분되거나(00-E0-91-31-55-04, 00:E0:91:31:55:04),
16bite 단위로 . 으로 구분 하여 사용된다(00E0.9131.5504).

펀드 총정리 !

Financial 2007/11/08 04:28

발췌 : http://cafe.naver.com/stocknjoy/38439


                                            -펀드 가입시 선택사항-

*적립식정액적릭식과 자유 적립식으로 분류되며 1년 이상 만기를 설정해야 한다.

정액적립식 - 매월 지정된 날짜에 일정 금액을 투자하는 방식

(원칙적으로는 부부환매 안되지만 펀드에 따라 부분환매가 되는것도 있으며 부분환매가 되도 추가매수가 안되는것과 되는것으로 분리됨^^좀 복잡하지만 펀드 가입시 숙지해둬야 한다 )

자유적립식 - 기간을 정하되 납입금액, 납입횟수에 제한이 없이 불입이 가능한것

(원칙적으로는 부부환매 안되지만 펀드에 따라 부분환매가 되는것도 있으며 부분환매가 되도 추가매수가 안되는것과 되는것으로 분리됨^^좀 복잡하지만 펀드 가입시숙지해둬야 한다. )

*임의식(자유적립식) -기간과금액에 상관없이 자유로운 투자를 하는 경우(부분환매 된다, 만기 설정없다)

정액적립,자유적립,임의식은 구분이 없다는 말의 있다~ 왜 그럴까?? ㅎㅎ

정액적립하다 돈없어서 돈 못넣고 나중에 넣으면 자유 적립 또는 임의식이 된다 .

임의식으로 하다가 정액적립식으로처럼 매월 지정된 날짜에 자동이체 하면  정액적립이된다.

단 부분환매와 만기설정의 차이가 있다.

*거치식 - 목돈을 장기간 예치하는 경우 (추가 매수가 안된다)


                                         - 클래스 분류 -

A클래스- 선취 수수료를 부과하는 펀드 (운용비는 가장 저렴하다)
C클래스- 선취,후취 수수료를 부과하지 않는 펀드 (운용비가 A보다 비싸다)
e클래스- C클래스와 똑같으나 인터넷 전용으로 운용비가 싸다.(운용비가 C보다 저렴하다)

A는 장기투자시 유리(보통 2년이상투자시) , C와 e는 단기투자시 유리할수 있음(보통1~2년)
그러나 펀드마다 운용비 설정이 다르기 때문에 위의 내용이 100%로 부합하지는 않으니..
자신의 생각하고 있는 투자기간을 고려하여 펀드 가입시 클래스 별로 따져 봐서 자신에게 가장 유리한 클래스의 펀드를 들어야 한다
.


                                          -그 외에 눈여겨 봐야 할것들-

운용보고서- 처음 펀드시작한  자라면 어려워 보일수 있으나 실제로 마음만 먹으면 그리 어렵지 않으며 펀드에 대한 가장 정확한 정보가 여기에 다 들어 있으니 필독해야 한다.

환매수수료-환매수수료의 개념은 조금은 복잡하여 자세하게 기술된 자료를 링크 걸어 놀께요^^

http://blog.naver.com/mobsters?Redirect=Log&logNo=50001566942

환매 대금 지급: 환매시 몇일 종가로 반영되어 몇일날 지급 받는지 알아두자.

ex) 3시이전 : 2영업일 기준가로 4영업일 지급
     3시이후 : 3영업일 기준가로 4영업일 지급

펀드 마다 다를수 있으니 이것 역시 확인해야한다~^^


                                              -추가매수 관련-

추가 매수 방법:  전화 , 인터넷

ex)미래에셋 디스커버리를 추가매수 할 경우..3시 이전에 추가매수시.. 오늘 종가=내일 기준가로 매수됨.
오늘 추가매수하면  예수금으로 잡혀 있다가  내일 실제 투자된다.  내일  확인해 보면 ....

원래 있던 원금 + 추가매수한 금액이 합쳐져서 원금이 된것을 확인 할수 있다.

              국내는 오후 3시이전에 추가매수시 오늘 종가=내일기준가로 매수됨.
              해외는 오후 5시이전에 추가매수시 오늘 종가=내일기준가로 매수됨.
펀드와 증권사에 따라서 조금은 다른 경우가 있으니 자신의 가입한 증권사에 문의하는게 가장 정확하다.


                                   -필자가 알고 있는 잡다한...정보와 Q&A-

1.동양종금 수수료 관련 Tip..

동양종금에서 월 10만원이상의 금융상품을 정기정액납부시 모든 입.출입 수수료가 무료이다..

필자의 경우 신영마라톤을 정기접릭식으로 설정하여 모든 수수료를 무료로 서비스 받고 있다..

단 부분환매하면 수수료 혜택이 없어지니 유념하자~

알아보면 무료로 이용가능한 여러 방법들이 있으니 받을 수 있는 혜택은 꼭 챙기도록 하자 ~ ~

2.설정일이란?

펀드의 생일로 펀드가 생겨난 날짜이다 . 이날은 펀드의 기준가가 1000으로 재설정된다.
만약 설정일 전날  기준가가 2000원이고 10만주를 가지고 있었다면 재설정후에는  기준가가 1000으로 설정되는 되신 20만주를 가지게 된다.(어떤한 손해,이익이 일어나지 않는다)
설정일 당일은 수익률을 확인해 보면..수익률의 변동이 심하게 나서 놀라는 분들이 있는데 기준가 재설정하면서 잠시 오류가 난 것이니 걱정안해도 된다. 오후나 다음날 확인해 보면 여지 없이 제대로 설정된 것을

확인 할 수 있다.

3. 추가매수시 수익율이 많이 떨어졌다?

추가매수 후에 수익율이 떨어진것을 보고 놀라서 질문하시는 분들도 가끔있는데 걱정안해도 된다.
원금이 커지니 수익율이 떨어지는 것이 당연하다.

4.  추가매수 타이밍 , 펀드 시작 시기

안탁까운 일이지만 그걸 자신있게 말해줄 수 있는 사람은 세상에 아무도 없다...
또한 단기적인 수익률은 .. 연연하지 않는게 건강에 좋다^^

예를 들어 보겠다.

ex)펀드를 시작하여 11개월동안 수익률이 30%났다고 가정해 보자.. 얼마나 좋겠는가? 히히;
근데 12개월되는 달..한달 사이에 수익률이 -25%가 났다면???(충분히 번번히 일어나는 일이다)OTL..
이제껏 조금이나마  더 이익보려고 매일 주가 확인하여 추가매수하고 매일 안절부절하고..했는데 결국은 이모든게 헛고생이 된 것이다...
고로 .. 단기적인 주가와 추가매수에 너무 연연하지 않아도 된다. 

말은 이렇게 하지만.. 사실 필자는  궁금하여.. 하루에도 몇번씩 확인한다는...ㅎㅎ

하여 펀드를 처음 시작하는 분들 또한  언제 들어올지  타이밍을 잴 필요는 없다.

적립식이라면  장이 꼭대기에 있든.밑바닥에 있던 상관없다.(미세한 차이는 있을 수 있지만...)

투자시기를 고민한다면  당장 시작하라가 가장 정답에 가까울 것 같다.

5.돈은 투자하지 않고 우선 펀드계좌만 만들수 있나?
펀드마다,증권사마다 다르다. 0원으로도 만들수 있는 펀드도 있고 요새 이슈인 인사이트처럼  1000만원이 있어야 만들수 있는 펀드가 있다.물론 지금은 금액제한이 풀렸다~

6.선취형 펀드의 경우는 선취수수료를 떼고 투자된다. 선취수수료가 1%로이면 10만원매수하면 9만9천10원이 투자된다. 가끔식 이것때문에 질문하시는 분이 있어서 적어봤다.

7.같은 펀드가 여러 증권사에서 판매되는 경우 어디에서 펀드를 가입해야 할까?
예들 들어 슈로더브릭스는 현재 미래에셋증권,우리투자증권,우리은행,국민은행,씨티은행,신한증권..등등에서 판매한다
이름이 같다면 어떤 곳에서 가입하나  똑같은 펀드니 어디서 가입하던 상관이 없다. 단..자신의 원하는 클래스를  판매 하는  곳으로 가야 할 것이다.
만약 슈로더 브릭스A형을 들고 싶다면 슈로더 브릭스A를 판매하는 미래에셋이나 외환은행을 가야한다. 우리투자증권이나 우리은행..등등은 현재 A형은 판매안하고  e형만 판매한다.

가끔? 아니 꽤 자주 위에것을 혼동하여 헛탕쳤다는 글들이 간간이 올라 온다..

8. 펀드에도 만기가 있는가?
있기도 하고 없기도 하다. 무슨 말인고 하니, 펀드 가입 시점 때 만기시점이 정해져 있는 경우가 대부분이지만,만기 시점이 도래했을 때 투자자가 계속 가져갈 의사를 투자운용사에 통보하면 계속 투자할 수 있는 경우가 있다. (일종의 만기 연장이 되는 셈이다.)
또는 환매하지 않고 그냥 놓아두어도 운용사는 거치식 개념으로 계속 재투자하게 된다. 이것은 투자운용사나 각각의 펀드마다 조금씩 다르기 때문에, 만기 시점을 앞두고 투자운용사에 문의, 상담하는 게 좋다..

9. 펀드도 분산하는 게 좋다고 하던데?
분산하는 게 좋기도 하고 좋지 않기도 하다. 무슨 말인고 하니, 위험 분산 차원에서 서로 상관관계가 적은 여러 개의 펀드에 나누어투자하는 게 좋다고 볼 수도 있고, 반면 한두 개의 펀드에 집중적으로 투자하여 높은 수익을 노리는 게 좋다고 볼 수도 있다.
사실 투자운용사나 판매사(주로 은행)들 입장에서는 하루에도 다양하게 쏟아져 나오는 펀드 상품들을 팔아야 하기 때문에, 다양한 펀드에 골고루 분산하라고 권하는 측면도 없지 않은 것 같다. 분산하려 한다면,

투자운용사를 분산할 수도 있고(예컨대 미래에셋, 한국투신운용, 삼성투신운용 등)
투자 지역을 분산할 수도 있고(한국, 유럽, 중국, 동유럽, 중남미, 인도 등등)
펀드 형태를 분산할 수도 있고(주식형, 채권형, 혼합형 등등)
펀드 성격을 분산할 수도 있고(특정 섹터 펀드, 중소형주 펀드, 대형주 위주 펀드 등등)
이런 다양한 분산 방식을 혼용하여 분산시킬 수도 있다.
다시 말해서 무조건 분산시킨다고 좋은 게 아니라, 투자자 자신의 투자 목적과 투자 성향에 따라 분산하는 게 좋다.

11. 환매는 언제하는 게 좋은가?

펀드 환매 시점은 제한이 없다. 만기 개념이 사실상 무의미하듯이, 환매도 자유롭다. 그러니 환매는 하고 싶을 때, 현금이 필요할 때 하면 된다.
 단, 펀드에 따라 가입 이후 일정 기간 내에 환매하면 환매수수료를 무척 많이 내게 하는 경우가 많다.
 하고 싶을 때 하면 된다는 건 반쯤은 농담이고(?), 자신이 기대했던 만족할만한 수준의 수익을 거두었다면 환매를 고려해 봐도 좋다.
그러나 권하고 싶기로는, 환매를 하더라도 전체를 환매하기보다는 부분 환매를 하는 게 좋다.
부분 환매도 수익분을 모두 환매하기보다는 수익분 가운데 일부를 환매하는 게 좋다.
수익분을 꼬박꼬박 다 환매하면 펀드의 덩치가 줄어들어 유사복리효과를 계속 거두기 힘들어지기 때문이다.
(물론 이 이야기는, 펀드 투자보다 수익율이 더 나은 투자처가 없는 경우에 해당하는 이야기다.)
전체를 다 환매한 다음에 막상 다른 투자처를 찾아봐도 별다른 게 없다면,
당신은 금방 후회하게 될 것이다. 급히 목돈을 써야 할 사정이 아니라면,
요컨대 펀드 투자금이 순수하게 투자에만 사용해서 돈을 불리기 위한 자금이라면,
 웬만하면 전체를 다 환매하지 말고 필요에 따라 수익분의 일부만 환매할 것을 권하고 싶다.

12. 도대체 어떤 펀드에 가입하는 게 좋은가?
그걸 자신있게 말해줄 수 있는 사람은 아무도 없다.
각자의 투자 목적과 성향과 판단에 달린 일이다.
단, 펀드 판매사, 즉 은행 창구에서 직원에게 권유받고 아무 생각없이 그냥 가입하는 것만은 절대 안된다.
판매사 직원들은 펀드 판매 실적이 자신의 인사 고과에서 중요하기 때문에 가능한 한 펀드 신상품,
또는 판매사가 한참 밀고 있는 펀드 상품 위주로 고객에게 권하게 되어 있다.
땀흘려 번 피 같은 내 돈을 투자하는 데, 그냥 은행 창구에서 5분도 안되는 시간 동안 대충 설명듣고 투자해서야 되겠는가?
자산운용사나 판매사 홈페이지에서 해당 펀드에 관한 사항을 자세히 읽어도 보고,
자산운용사 측에 문의해서 이것저것 따질 거 다 따져보고 신중을 기하는 게 좋다.
작년 수익율 또는 현재의 수익율이 1등인 펀드라고 해서 무조건 가입하는 것도 말리고 싶다.
디스커버리도 한때는 수익율이 저조하여 평판이 안좋았다고 한다. 
펀드 수익율은 순위는 해마다 변화무쌍하다.
신상품 펀드가 아니라면 지난 몇 년 간 꾸준한 수익율을 기록해왔는가가 당장의 수익율 순위보다 더 중요하다.
그리고 펀드 초보자라면 가능한 한 실적이 검증된 대형 운용사들(어디라고 말 안해도 알 것이다.)
이 운용하는 대형 펀드(운용 금액 덩치가 상대적으로 큰)에 가입하는 게 안전하다.
운용사들마다 운용사의 얼굴 구실을 하는 대표적인 펀드가 있기 마련인데, 그런 펀드에 가입하는 것도 안전한 편이다.
 그런 펀드에 우선 가입해놓고 펀드에 관해 좀 더 경험하고 알아볼 것은 알아보고 하면서 펀드에 관한 경험과 지식이 늘어나면,펀드를 보는 눈 같은 게 생기게 되어 있다.

13. 펀드도 점검과 갈아타기가 필요한가?
기대한만큼 수익을 올리지 못하는 펀드도 적지 않다. 그런 펀드라면 오래 가져가기보다는 환매해서 다른 펀드로 갈아탈 필요도 있다.
 주식시장 자체가 하락 장세여서 대부분의 펀드들이 고전하고 있다면 또 모르겠지만,
그렇지 않은데도 다른 펀드들(내 펀드와 비슷한 성격의)에 비해 수익율이 많이 떨어진다면, 환매와 갈아타기를 고민해봐야 한다.

14. 왠만하면 적립식으로 투자하는 게 좋다는 까닭은?

그러나 대부분의 투자자들은 펀드 계좌에 월 일정액을 적금 납입하듯이 자동 이체시킨다.
그 편이 편리하기도 하고, 투자 시점을 일정하게 분산시킴으로써 위험을 분산시키는 효과를 거둘 수 있기 때문이다.
주식시장 상황이 좋을 때는 그만큼 수익을 많이 거둘 수 있고, 주식시장 상황이 좋지 않을 때는 그만큼 상대적으로 싼 값에 주식을 매수하는 효과가 나기 때문이다. (나중에 시장 상황이 좋아지면, 싼 값에 산 주식이 위력을 발휘할 수 있다.)
주가는 주기가 짧든 길든 등락을 반복하게 되어 있고, 그 등락 추이에 정확하게 맞춰서 투자하기는 사실상 어렵다고 할 때,일정 주기로 분산해서 투자하면 하락에 따른 손실 위험을 분산시키고, 상승에 따른 수익도 기대할 수 있다.

15. 그럼에도 거치식으로 투자하는 사람이 있던데?

전체적으로 비교하면 거치식이 적립식에 비해 수익율이 높기 때문이다. 한 꺼번에 목돈을 적립해 놓는 것이기 때문에, 적립식보다 거치식에서 높은 수익율을 기대할 수 있다. 그러나 주식시장 상황이 제법 오랜 기간 좋지 않거나,널뛰기 식으로 등락을 거듭하는 변동성 장세라면 거치식은 위험해진다.
그러나 비교적 오랜 기간 꾸준히 상승하는 대세 상승장이라면,거치식의 수익율이 매우 높게 나타나는 경우가 많다.  요컨대 거치식은 적립식에 비해 고위험고수익 투자 형태에 해당한다고 할 수 있다.



Eclipse : 3.1.1
이후 버젼은 다 지원되는듯 하다.
그 이전 버젼은 확인을 해보지 않아서 잘 모르겠다.

Window - Preferences
General - Editors - Text Editors - Accessibility 에서
Use characters to show changes on line number bar 선택후 Apply.

사용자 삽입 이미지


설정후 테스트 해보면...

1. 기존라인에 입력된 내용 수정시 "~" 표시.
2. 새로운 줄이 추가될 경우 "+" 표시.

원문 : http://polly97.wordpress.com/2007/06/13/java-theory-and-practice-jts-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%B3%B4%EC%95%88%EA%B3%BC-%ED%8D%BC%ED%8F%AC%EB%A8%BC%EC%8A%A4-%EA%B7%A0%ED%98%95%EB%A7%9E%EC%B6%94%EA%B8%B0/

2002 년 5 월 01 일
2003 년 1 월 21 일 수정

JTS 시리즈를 통해 Brian은 트랜잭션의 기초와 J2EE 컨테이너가 트랜잭션 서비스를 EJB 컴포넌트에 투명하게 할 수 있는지를 설명했다. 이번에는 트랜잭션 경계화와 고립화 관리에 필요한 J2EE 기능을 설명한다. 또한 그들을 효과적으로 사용할 수 있는 가이드라인도 제시한다.

Part 1 (”JTS 이해하기 - 트랜잭션에 대한 소개“)과 Part 2 (”JTS 이해하기 - 장막 뒤의 마법 “)에서 트랜잭션이 무엇인지를 정의했고 트랜잭션의 기본 속성, Java Transaction Service와 J2EE 콘테이너가 함께 작동하여 J2EE 컴포넌트를 지원하는 방법을 설명했다. 이제는 트랜잭션 경계화(demarcation)와 고립(isolation)에 대해 알아보자.

EJB 컴포넌트의 트랜잭션 경계화와 고립 속성을 정의하는 책임은 애플리케이션 어셈블러에 있다. 이들을 부적절하게 설정하면 퍼포먼스, 확장성, 애플리케이션의 내구성에 심각한 결과를 초래할 수 있다. 불행히도 이러한 속성들을 적절히 설정하는 데에 정해진 규칙 같은 것은 없다. 다만 병행성 위험과 퍼포먼스 위험 사이에서 균형을 찾도록 도와주는 가이드라인이 있을 뿐이다.

Part 1에서 다루었듯이 트랜잭션은 기본적으로 예외 처리(exception-handling) 매커니즘이다. 무엇인가 잘못되었다면 복구할 수 있도록 도와준다. 실제로 나쁜 상태가 되는 것은 거의 없기 때문에 비용과 시간 할애를 최소화 할 수 있다. 애플리케이션에서 트랜잭션을 사용하는 방법에 따라 애플리케이션 퍼포먼스와 확장성에 큰 영향을 미칠 수 있다.

트랜잭션 경계화

J2EE 콘테이너는 트랜잭션이 어디에서 시작하고 끝나는지를 정의하는 두 가지 매커니즘 (빈 관리(bean-managed) 트랜잭션과 콘테이너 관리(container-managed) 트랜잭션)을 제공한다. 빈 관리 트랜잭션의 경우 UserTransaction.begin()UserTransaction.commit()을 이용하여 빈(bean) 메소드에서 트랜잭션을 시작하고 끝낸다. 반면, 콘테이너 관리 트랜잭션의 경우 좀 더 많은 유연성을 제공한다. 어셈블리 디스크립터에 각 EJB 메소드를 위한 트랜잭션 속성을 정의함으로서 각 메소드 별로 트랜잭션 요구사항이 무엇인지를 지정할 수 있고 콘테이너가 트랜잭션을 언제 시작하고 끝내야 하는지를 결정하도록 할 수 있다. 두 경우 모두 트랜잭션을 설계하는 기본 가이드라인은 같다.

위로

전략

트랜잭션 경계화의 첫 번째 규칙은 “짧게 유지할것!” 트랜잭션은 병행 제어를 제공한다. 이것은 리소스 매니저가 트랜잭션 과정 중에 액세스한 데이터 아이템을 대신하여 lock을 얻어 트랜잭션이 끝날때까지 그들을 보유하고 있어야 한다는 것을 의미한다. 여러분이 lock을 보유하고 있는 동안에 다른 트랜잭션은 lock을 해제할 때까지 기다린다. 트랜잭션이 매우 길어지면 모든 다른 트랜잭션들은 저지당하고 애플리케이션 쓰루풋은 내려가기 마련이다.

Rule 1: 트랜잭션을 가능한 한 짧게 유지하라!

트랜잭션을 짧게 유지함으로서 애플리케이션의 확장성을 향상시킨다. 트랜잭션을 가능한 짧게 유지하는 최상의 방법은 트랜잭션의 중간에 불필요하게 시간을 허비하는 어떤 작업도 수행하지 않고 특별히 트랜잭션의 중간에 사용자 인풋을 기다리지 않는다.

트랜잭션을 시작하고 데이터베이스에서 데이터를 도출하여 데이터를 디스플레이하고 사용자에게 트랜잭션 동안 선택을 하도록 요청하고 싶을 것이다. 하지만 이렇게 하지 말기를 바란다. 사용자가 주의를 기울이더라도 응답하기 까지는 수 초가 걸리고 이는 데이터베이스에서 lock을 보유하기엔 긴 시간이다. 사용자가 점심을 먹거나 집에 가기위해 컴퓨터에서 물러나기라도 한다면 어떻게 될까? 애플리케이션은 간단히 멈추게 될 것이다. 트랜잭션 도중에 I/O를 수행하는 것은 재앙으로 가는 비결이다.

Rule 2: 트랜잭션 도중 사용자 인풋을 기다리지 말것!

위로

관련 오퍼레이션을 함께 그룹핑 할 것

각 트랜잭션은 중대한 오버헤드를 갖고있기 때문에 오퍼레이션 당 오버헤드를 최소화하기위해 단일 트랜잭션에서 가능한 많은 오퍼레이션을 수행하는 것이 최상의 방법이라고 생각할 수도 있다. 하지만 Rule 1에 따르면 긴 트랜잭션은 확장성에 나쁘다고 한다. 그렇다면 오퍼레이션당 오버헤드를 줄이는 것과 확장성 사이의 균형을 어떻게 맞추면 되는가?

Rule 1–트랜잭션 당 한 오퍼레이션–을 논리적 마지막 수단으로 취한다면 추가적인 오버헤드를 가져올 뿐 아니라 애플리케이션 상태의 일관성도 타협하게 된다. 트랜잭션 리소스 매니저는 애플리케이션 상태의 일관성을 관리하도록 되어있다. 하지만 그들은 일관성을 정의하기 위해 애플리케이션에 의존한다. 사실 트랜잭션을 설명할 때 우리가 사용하는 일관성의 정의는 다소 모호하다. 일관성은 애플리케이션이 말하는 모든것을 의미한다.

Part 1에서는 한 어카운트에서 다른 어카운트로 자금을 이동하는 뱅킹 애플리케이션 예제를 보았다. Listing 1은 SQL로 할 수 있는 구현을 보여준다. 다섯 개의 SQL 작동이 포함되어있다:
Listing 1. 자금 이체용 SQL 코드 샘플



SELECT accountBalance INTO aBalance

    FROM Accounts WHERE accountId=aId;

IF (aBalance >= transferAmount) THEN

    UPDATE Accounts

        SET accountBalance = accountBalance - transferAmount

        WHERE accountId = aId;

    UPDATE Accounts

        SET accountBalance = accountBalance + transferAmount

        WHERE accountId = bId;

    INSERT INTO AccountJournal (accountId, amount)

        VALUES (aId, -transferAmount);

    INSERT INTO AccountJournal (accountId, amount)

        VALUES (bId, transferAmount);

ELSE

    FAIL "Insufficient funds in account";

END IF

다섯 개의 개별 트랜잭션으로서 이 오퍼레이션을 실행한다면 어떤 일이 발생할까? 느려지는 것은 물론 일관성도 잃게된다. 예를들어 누군가가 첫 번째 SELECT 실행과 연속적인 차변 UPDATE 사이에 개별 트랜잭션으로 일부로서 A 어카운트에서 돈을 인출한다면 어떻게 될까? 이것은 이 코드에 의해 시행되어야 하는 비지니스 규칙을 위반한 것이 된다. 시스템이 첫 번째 UPDATE와 두번째 UPDATE 사이에서 고장난다면 어떻게 될까? 시스템이 복구되면 돈은 A 어카운트에 남아있게 되지만 B 어카운트에 기입되지 않게되고 이유는 기록되지 않는다. 이것은 두 계정의 소유자에게 안좋은 일이다.

Listing 1의 다섯 개의 SQL 오퍼레이션은 하나의 관련된 오퍼레이션으로 볼 수 있다. 즉 돈을 한 어카운트에서 다른 어카운트로 전송하는 것을 의미한다. 그러므로 우리는 모든것이 실행되거나 아예 실행되지 않거나 하기를 바라는 것이다. 그들이 단일 트랜잭션에서 모두 실행되어야 하는 이유가 바로 이것이다.

Rule 3: 관련 오퍼레이션을 단일 트랜잭션으로 그룹핑 할것!

위로

이상적인 균형

Rule 1은 트랜잭션이 되도록이면 짧아져야 할 것을 요구하고 있다. Listing 1의 예제에서는 일관성을 유지하기 위해서 가끔은 오퍼레이션들을 하나의 트랜잭션으로 묶어야 한다는 것을 보여주었다. 물론 이 모든 것은 어떤 구성요소들이 “관련 오퍼레이션”인지를 결정하는 애플리케이션에 의존한다. Rule 1과 3을 조합하여 트랜잭션의 범위를 설명하는 일반적인 가이드라인을 만들수 있다. 이것이 Rule 4 이다:

Rule 4: 관련 오퍼레이션을 단일 트랜잭션으로 그룹핑하라. 단, 연관성 없는 오퍼레이션은 개별 트랜잭션으로 놓을것!

위로

콘테이너 관리 트랜잭션

콘테이너 관리 트랜잭션을 사용할 때, 트랜잭션이 어디서 시작하여 어디에서 끝나는지를 명확히 설명하는 대신 각 EJB 메소드를 위한 트랜잭션 요구사항을 정의한다. 트랜잭션 모드는 빈의 assembly-descriptorcontainer-transaction 섹션의 trans-attribute 엘리먼트에 정의되어 있다. 메소드의 트랜잭션 모드는 호출 메소드가 트랜잭션이 이미 포함되어 있는지의 여부를 나타내는 상태와 더불어 EJB 메소드가 호출 될 때 콘테이너가 어떤 액션을 취할지 결정한다:
Listing 2. EJB 어셈블리 디스크립터 샘플



<assembly-descriptor>

  ...

  <container-transaction>

    <method>

      <ejb-name>MyBean</ejb-name>

      <method-name>*</method-name>

    </method>

    <trans-attribute>Required</trans-attribute>

  </container-transaction>

  <container-transaction>

    <method>

      <ejb-name>MyBean</ejb-name>

      <method-name>logError</method-name>

    </method>

    <trans-attribute>RequiresNew</trans-attribute>

  </container-transaction>

  ...

</assembly-descriptor>

J2EE 스팩은 여섯 개의 트랜잭션 모드를 정의한다: Required, RequiresNew, Mandatory, Supports, NotSupported, Never. Table 1은 각 모드의 작동을 요약해 놓은 것이다. 기존 트랜잭션에 있을 때 호출될 때와 트랜잭션에 없을 때 호출 될 경우로 분류했다. 각 모드를 지원하는 EJB 컴포넌트 유형도 설명했다

Table 1. 트랜잭션 모드

트랜잭션 모드 빈 유형 T 트랜잭션에 있을 때 호출될 경우의 액션 트랜잭션 밖에서 호출될 때의 액션
Required Session, Entity, Message-driven T에 포함 새로운 트랜잭션
RequiresNew Session, Entity 새로운 트랜잭션 새로운 트랜잭션
Supports Session, Message-driven T에 포함 트랜잭션 없이 실행
Mandatory Session, Entity T에 포함 Error
NotSupported Session, Message-driven 트랜잭션 없이 실행 트랜잭션 없이 실행
Never Session, Message-driven Error 트랜잭션 없이 실행

콘테이너 관리 트랜잭션만을 사용하는 애플리케이션에서, 트랜잭션을 시작할 수 있는 유일한 방법은 트랜잭션 모드가 Required 또는 RequiresNew인 EJB 메소드를 컴포넌트가 호출할 경우이다. 콘테이너가 호출한 결과로서 트랜잭션을 만들 때, 그 트랜잭션은 메소드가 완료될 때 닫힌다. 메소드가 정상적으로 리턴되면 콘테이너는 트랜잭션을 발생시킨다. 예외를 주어 메소드가 종료하면 콘테이너는 트랜잭션을 롤백(roll back)하고 예외를 선언한다. 메소드가 기존 T 트랜잭션에 있을 때 호출되고 그 트랜잭션 모드는 메소드가 트랜잭션 없이 실행되거나 새로운 트랜잭션에서 실행되어야 한다는 것을 지정하면, T 트랜잭션은 메소드가 완료될 때 까지 중지하고 이전의 T 트랜잭션은 시작된다.

위로

트랜잭션 모드 선택하기

빈 메소드를 위해 어떤 모드를 선택해야 할까? 세션과 message-driven bean의 경우 모든 호출이 트랜잭션의 일부로서 실행될 것을 확인하기 위해 Required를 사용해야 하지만 메소드가 더 큰 트랜잭션의 컴포넌트가 되도록 할 수 있다. RequiresNew로 시도해보자. 이것은 메소드의 작동이 호출된 메소드의 행동과 개별적으로 이루어진다는 것을 확신할 때만 사용될 수 있다. RequiresNew는 전형적으로 시스템에서 다른 객체들과 관련이 없는 객체를 가지고 사용된다.

CMP (container-managed persistence) 엔터티 빈의 경우, Required를 사용해야 할 것이다. Mandatory 또한 합당한 옵션이 될 수 있는데 특별히 초기 개발에 맞다. CMP 엔터티빈에 RequiresNew 를 사용할 수는 없다. NotSupportedNever는 비 트랜잭션 리소스용이다.

EJB 애플리케이션이 올바르게 디자인될 때 트랜잭션 모드에 대한 위 가이드라인은 Rule 4의 트랜잭션 경계화를 만들어낸다. J2EE 아키텍쳐는 애플리케이션을 가장 작은 프로세싱 청크로 분해되는 것을 장려한다.

위로

고립

Part 1에서, 고립(isolation)은 한 트랜잭션의 효과가 동시에 실행하고 있는 다른 트랜잭션에 보이지않는 것이라고 정의했다. 트랜잭션의 관점에서 트랜잭션은 병렬보다는 순차적으로 실행한다. 트랜잭션 리소스 매니저가 많은 트랜잭션들을 동시에 프로세스 하면서 “고립의 환상”을 제공한다. 가끔씩 고립의 제약조건은 새로운 트랜잭션 시작을 기존 트랜잭션이 완료될 때까지 미루도록 한다. 트랜잭션을 완료하는 것에는 적어도 하나의 동기식(synchronous)의 디스크 I/O가 포함되어있기 때문에 초당 트랜잭션의 수를 초당 디스크 쓰기의 수로 제한할 수 있다. 이것은 확장성에 좋지 않다.

실제로 고립 요구조건을 풀어서 더 많은 트랜잭션들이 동시에 실행될 수 있도록 하고 시스템 응답과 더 나은 확장성으로 향상시킬 수 있다. 거의 모든 데이터베이스는 네 개의 표준 고립 레벨을 지원한다: Read Uncommitted, Read Committed, Repeatable Read, Serializable.

콘테이너 관리 트랜잭션을 위한 고립 관리는 현재 J2EE 스팩의 범위를 벗어나있다. 하지만 IBM WebSphere와 BEA WebLogic 같은 많은 J2EE 콘테이너는 콘테이너 스팩의 확장을 제공하여 트랜잭션 모드가 어셈블리 디스크립터에 설정되는 것과 같은 방식으로 메소드 기반으로 트랜잭션 고립 레벨을 설정할 수 있다. 빈 관리 트랜잭션의 경우 JDBC 또는 다른 리소스 매니저 커넥션을 통해 고립 레벨을 설정할 수 있다.

고립 레벨 간 차이점을 보기위해 여러가지 병행성 위험을 분류해 보겠다. 다음 위험요소들 모두는 두 번째 트랜잭션이 이미 시작한 후에도 첫 번째 트랜잭션이 두 번째 트랜잭션에 보여진 결과와 연관되어있다:

네 개의 표준 고립 레벨은 이러한 세 개의 고립 위험과 관련되어있다. (Table 2). 가장 낮은 고립 레벨은 Read Uncommitted 로서 다른 트랜잭션에서 이루어진 변경을 막지 못한다. 하지만 읽기 lock에 대한 경쟁(contention)을 요구하지 않기 때문에 가장 빠르다. 가장 높은 고립 레벨인 Serializable은 위에 제사한 고립의 정의와 일치한다. 각 트랜잭션은 다른 트랜잭션의 효과로부터 완전히 고립된다.

Table 2. 트랜잭션 고립 레벨

고립 레벨 Dirty read Unrepeatable read Phantom read
Read Uncommitted Yes Yes Yes
Read Committed No Yes Yes
Repeatable Read No No Yes
Serializable No No No

대부분의 데이터베이스 경우 기본 고립 레벨은 Read Committed 인데 트랜잭션의 어떤 지점에서도 애플리케이션 데이터가 보이는 것을 방지해주기 때문에 유용하다. Read Committed는 가장 전형적인 짧은 트랜잭션에 사용하기 알맞은 고립 레벨이다.

높은 수준의 고립인 Repeatable Read와 Serializable은 트랜잭션 전체에서 높은 수준의 일관성이 필요할 때 알맞다. 데이터 일관성이 절대적으로 필요한 경우 새로운 열 생성을 방어할 필요가 있다. 이때 Serializable을 사용해야 한다.

가장 낮은 고립 레벨인 Read Uncommitted는 거의 쓰이지 않는다. 정확하지 않는 값을 얻고자 할 때 쓰이며 질의는 예기치 않은 퍼포먼스 오버헤드를 만들게 된다. 주문 수량 또는 당일 주문받은 달러 같이, 빠르게 수량을 계산할 때에는 Read Uncommitted가 전형적으로 사용된다.

고립과 확장성 사이에는 모순이 존재하기 때문에 트랜잭션에 고립 레벨을 선택할 때에는 특별한 주의를 기울여야 한다. 너무 낮은 레벨을 선택하면 데이터에 위험부담이 생긴다. 또, 너무 높은 레벨을 선택하면 퍼포먼스에 좋지 않다. 일반적으로 데이터 일관성 문제는 퍼포먼스 문제보다 더 심각하다:

Rule 5: 데이터를 안전하게 하는 가장 낮은 고립 레벨을 사용하되 불확실할 경우 Serializable을 사용할것!

컴포넌트를 개발 할 때 고립의 요구 사항에 대해 신중하게 생각해봐야 한다. 만약 퍼포먼스가 문제가 된다면 나중에 당황하지 않도록 낮은 고립 레벨도 견딜 수 있는 트랜잭션을 작성해야 한다. 어떤 메소드가 작동하고 고립 레벨을 정확히 설정하기 위한 일관성 전제조건이 무엇인지를 알 필요가 있으므로 개발하면서 일관성 요구사항과 전제조건을 세심하게 문서화 하는 것이 좋다.

위로

결론

이 글에 제시된 가이드라인들이 다소 모순처럼 보인다. 트랜잭션 경계화와 고립은 근본적으로 모순 그 자체이기 때문이다. 안전성과 툴의 퍼포먼스 오버헤드사이의 균형을 유지해야 한다.

위로

참고자료