Flex3 유용한 사이트

Flex 2009. 4. 23. 02:42
http://examples.adobe.com/flex3/componentexplorer/explorer.html
- Flex3 각 컴포넌트들의 실제 작동하는 예제와 소스코드를 제공

http://livedocs.adobe.com/flex/3/langref/
- Flex3 모든 컴포넌트들의 상속관계, 속성, 스타일 등을 찾을 수 있다

http://livedocs.adobe.com/flex/3/html/index.html
- Flex3 help 페이지인데 주로 왼쪽의 검색창에서 알고 싶은 내용의 설명이나 예제를 찾는 데 사용

http://blog.flexexamples.com/
- Flex에 대해 어느 정도 감을 잡고 이것저것 응용하기 시작하면서부터 필요한 아주 다양한 예제가 있는 곳

'Flex' 카테고리의 다른 글

Flex에서 Java의 HashMap과 같은 기능 사용  (0) 2009.05.15
Flex에서 HTML 페이지 띄우기  (0) 2009.05.14
Flex 3 + BlazeDS  (0) 2009.04.16
로딩속도 향상  (0) 2009.04.13
FormItem 안의 내용을 옆으로 배치  (0) 2009.04.13
AND

Flex 3 + BlazeDS

Flex 2009. 4. 16. 23:49
기본적으로 Flex는 화면단만을 개발할 수 있다.
(기본제공 컴포넌트가 다양해서 일반적인 화면은 쉽게 개발할 수 있고, 기본제공 컴포넌트로 구현할 수 없는 복잡한 화면은 기본 컴포넌트를 상속해서 확장하거나 ActionScript 코딩을 통해 구현하면 된다.)
다수의 사용자가 접속하는 시스템의 경우 애플리케이션 서버에 DB 등에 접속하는 코드가 있고, 이 코드와 Flex로 구현한 화면간의 통신을 구현해야 한다.
화면단의 Flex와 서버간의 통신기능을 제공하는 유료제품으로 Adobe의 LiveCycle Data Service가 있다. 그런데, 이것을 사용해서 시스템을 구축하면 운영서버의 CPU수에 따라 라이센스 비용을 지불해야 한다. 이 비용이 꽤 비싼 것으로 알고 있다. 우리나라에선 Flex Builder도 외국에 비해 상당히 비싼데, LCDS까지 이렇게 비싸니 우리나라에서 Flex가 빨리 보급되지 못 하는 이유 중 하나라고 생각된다.
LCDS에 대한 대안으로 아이러니하게도 Adobe에서 BlazeDS라는 것을 제공한다. 이것은 오픈소스로 무료로 사용할 수 있다. LCDS는 Flex Builder에서 편리하게 개발할 수 있는 기능을 제공하지만, BlazeDS는 Flex Builder에는 기능이 제공되지 않아 약간의 수작업이 필요하다. 하지만 약간의 유틸리티를 이용하면서 구성만 잘 하면 비용대비 효과가 우수한 시스템을 구축할 수 있다.

(이하 내용은 제가 사용하면서 예측한 내용으로 사실과 다를 수 있음을 알려 드립니다)
BlazeDS는 Flex로 구현된 화면단과 J2EE로 구현된 서버단간에 HTTP로 데이터를 원활히 주고 받을 수 있도록 연결해 주는 역할을 수행한다. 서버단에서 수행되는 메커니즘을 보면 Struts하고 유사하다고 보면 된다. 화면에서 특정 이름으로 서버단의 BlazeDS 서블릿을 호출하면, 서블릿은 그 이름에 해당하는 클래스를 XML 설정파일에서 찾아 객체를 생성하고 해당 메소드에 인자를 넘겨 호출한 후 결과를 리턴한다. 여기서 중요한 역할이 화면단에서 ActionScript 형태로 만들어 보낸 인자를 그에 맞는 Java 객체로 변환해서 메소드에 전달하는 것과 해당 메소드의 처리결과(Java 객체)를 Flex 화면에서 받을 수 있도록 전달해 주는 것이다. BlazeDS의 이런 역할 덕분에 Flex 화면과 J2EE 웹컨테이너간의 통신이 가능하다.
여기서, 서블릿이 특정 이름에 대해 호출하는 클래스는 특별한 제약이 없이 POJO면 가능하다. 즉, 여기부턴 자유롭게 구성이 가능하므로 예를 들면 Spring으로 이후를 구성할 수도 있다는 뜻이다. 아니면 Struts2의 Action처럼 클래스를 구현하고 DB처리는 Hibernate나 iBatis로 구현해도 된다.

대형 시스템을 구성한다면 BlazeDS를 이용해서 서버단 라이센스 비용을 대폭 줄일 수 있겠고, 대신 Flex Builder는 개발자수만큼 사야 될 것이다. Flex Builder는 기본과 Pro 버전이 있는데 기본이 1명당 40만원 정도였던 것 같고, Pro는 백만원이 넘었던 것으로 기억한다.(환율따라 자주 변함) Pro는 Advanced DataGrid라고 DataGrid에 트리형태의 표현 등 기능이 추가된 것과 차트 기능이 추가된다. 본인은 유료 Pro 버전을 쓰고 있는데 Advanced DataGrid는 별로 쓸 일이 없었고, 차트 기능은 편리해서 잘 사용하고 있다. 개발자가 많다면 대부분은 기본버전을 구매하고, 한두명만 Pro버전을 구매해서 이 사람들에게 차트개발을 몰아주는 것도 방법이 될 수 있을 것 같다. 솔직히 Flex 써 보니 사용하기도 괜찮고 모양도 예쁘게 만들어져서 좋긴 한데 우리나라에선 너무 비싸게 파는 것 같다.

참고로 Flex Builder는 3.0 말고 3.2 이상을 쓰는 것이 좋다. 맨 처음 3.0 썼는데 소스 하나 고치고 저장할 때마다 빌드시간이 너무 오래 걸려서 짜증났는데, 3.2 쓰면서 빌드 시간이 거의 5초 이내로 줄어서 쓸만해졌다.
참고 또 하나, Flex와 BlazeDS로 현재 개발환경을 구성한다면 Eclipse 3.4 (Ganymede)에 Flex Builder 3.2 Eclipse Plugin 버전을 사용하면 된다. Eclipse 3.3에서 3.4로 버전업 되면서 다른 건 몰라도 Search 결과는 참 보기 좋게 바뀌었다. 그래서, 3.4 강추!
-> 얘길 들어보니 Flex Builder 3.2를 써도 Eclipse 3.3을 쓰면 빌드 시간이 여전히 길다고 하니 반드시 Flex Builder 3.2에 Eclipse 3.4의 조합이 최적인 것 같다.

이와 관련된 링크나 설치방법, 샘플 등은 본인이 워낙 게으른 관계로 제공하지 못 하고, 그냥 열심히 해 보시라는 말 밖에 못 드리는 점 양해 바랍니다.

'Flex' 카테고리의 다른 글

Flex에서 HTML 페이지 띄우기  (0) 2009.05.14
Flex3 유용한 사이트  (0) 2009.04.23
로딩속도 향상  (0) 2009.04.13
FormItem 안의 내용을 옆으로 배치  (0) 2009.04.13
Label, TextInput에 손 모양 커서 적용  (0) 2009.04.13
AND

로딩속도 향상

Flex 2009. 4. 13. 16:02
ViewStack이나 TabNavigator 등 다른 컴포넌트들을 포함하면서
필요에 따라 일부는 보여주고, 나머지는 숨기는 레이아웃 컴포넌트들이 있다.
이런 것들은 creationPolicy라는 속성이 있는데,
이 속성값을 all로 하면 ViewStack이나 TabNavigator를 생성할 때 포함된 컴포넌트까지 모두 생성하고(포함된 컴포넌트가 많을수록 로딩속도가 느려짐),
auto로 하면 포함된 컴포넌트를 보여달라는 요청이 올 때에 컴포넌트를 생성한다.
(ViewStack은 해당 화면을 보여 줄 때, TabNavigator는 해당 탭을 선택했을 때)

그러므로, Application 안의 ViewStack에 업무화면들을 잔뜩 쌓아 놓고 메뉴에 따라 보여주는 형태라면 이 ViewStack의 creationPolicy를 auto로 하는 것이 로딩속도 향상에 좋다.
책을 보면 로딩속도 향상을 위해 작은 단위로 module을 만들어 놓고 필요할 때마다 moduleLoader 같은 걸로 띄우라고 하는데 귀찮아서 이것저것 보던 중에 creationPolicy라는 좋은 속성을 발견해서 쉽게 해결했다.
단, ViewStack에 creationPolicy를 설정하면 그 안에 포함된 화면 안에 있는 ViewStack이나 TabNavigator들에 creationPolicy 설정하지 않으면 상위 컴포넌트의 creationPolicy를 따라간다.

경험상 Application 안의 ViewStack 외에 그 안에서 사용하는 ViewStack이나 TabNavigator는 creationPolicy를 all로 하는 게 좋다. auto로 하면 안 보이는 탭이나 화면의 컴포넌트들이 null 상태인데, 이 때 안 보이는 컴포넌트들을 참조하려고 하면 맨 처음 한 번은 null 오류가 발생하기 때문이다.

'Flex' 카테고리의 다른 글

Flex3 유용한 사이트  (0) 2009.04.23
Flex 3 + BlazeDS  (0) 2009.04.16
FormItem 안의 내용을 옆으로 배치  (0) 2009.04.13
Label, TextInput에 손 모양 커서 적용  (0) 2009.04.13
문자열 클립보드에 저장  (0) 2009.04.12
AND

일반적으로 입력/수정 폼 형태에는 Form 컴포넌트를 사용하는 게 좋다.
그런데, 한 내용에 가로로 2개의 입력이 필요할 경우에는 FormItem의 direction 속성을 horizontal로 설정하면 된다. 이 속성을 사용하지 않으면 세로로 위치한다.

<mx:FormItem label="비밀번호" labelWidth="200" direction="horizontal">
  <mx:TextInput id="pw1" width="200"/>
  <mx:TextInput id="pw2" width="200"/>
</mx:FormItem>

'Flex' 카테고리의 다른 글

Flex3 유용한 사이트  (0) 2009.04.23
Flex 3 + BlazeDS  (0) 2009.04.16
로딩속도 향상  (0) 2009.04.13
Label, TextInput에 손 모양 커서 적용  (0) 2009.04.13
문자열 클립보드에 저장  (0) 2009.04.12
AND

Label과 TextInput에 click 이벤트 처리하면 스크립트를 실행시킬 수는 있다.
그런데, click 이벤트 처리한다고 여기에 마우스를 올렸을 때 자동으로 마우스 커서가 손모양으로 바뀌진 않는다.
아래의 3개 속성을 설정해 주어야 된다.

useHandCursor="true"
buttonMode="true"
mouseChildren="false"

물론 다른 컴포넌트도 적용할 수 있을 것 같긴 한데 내가 적용해 본 것은 여기까지.
내 생각엔 useHandCursor 하나만으로 적용되어야 할 것 같은데 3개나 해 줘야 하다니...

'Flex' 카테고리의 다른 글

Flex3 유용한 사이트  (0) 2009.04.23
Flex 3 + BlazeDS  (0) 2009.04.16
로딩속도 향상  (0) 2009.04.13
FormItem 안의 내용을 옆으로 배치  (0) 2009.04.13
문자열 클립보드에 저장  (0) 2009.04.12
AND

문자열 클립보드에 저장

System.setClipboard(dataString);

이 스크립트가 실행된 뒤엔 Ctrl+V하면 아마 이 내용이 붙겠지.

'Flex' 카테고리의 다른 글

Flex3 유용한 사이트  (0) 2009.04.23
Flex 3 + BlazeDS  (0) 2009.04.16
로딩속도 향상  (0) 2009.04.13
FormItem 안의 내용을 옆으로 배치  (0) 2009.04.13
Label, TextInput에 손 모양 커서 적용  (0) 2009.04.13
AND


대단한 프로그램은 아니고,
이번에 프로그램을 한참 개발하고 다국어 버전으로 변경할 일이 있었는데
30여개의 소스 파일을 일일이 뒤지면서 한글로 만들어 놓은 코드를 다국어 처리코드로 바꾸는 게 여간 힘든 작업이 아니었다.
(눈과 팔이 너무 아팠다. ^^;)
만만하게 보고 그냥 무식하게 하려다가, 결국 반 정도를 한 후에 프로그램을 만들었다. ^^;

아래에 있는 소스가 자바로 만든 변환 프로그램.

[code java]
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;

public class I18NReplace {
    private static final String I18N_CODE_PREFIX = "{resourceManager.getString('rb','";
    private static final String I18N_CODE_POSTFIX = "')}";

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        HashMap map = new HashMap();
        BufferedReader br = null;
        BufferedReader brSrc = null;

        try {
            // 다국어 코드, 값이 정의된 리소스번들 파일
            br = new BufferedReader(new InputStreamReader(
                                    new FileInputStream("code.properties"), "UTF-8"));
            // 다국어 버전으로 변환할 소스 파일
            brSrc = new BufferedReader(new InputStreamReader(
                                    new FileInputStream("test.mxml"), "UTF-8"));
           
            String line = null;
            // 다국어 코드, 값을 HashMap에 저장
            while ( (line = br.readLine()) != null ) {
                String[] arr = line.split("=");
                if (arr.length == 2) {
                    map.put(arr[0], arr[1]);
                }
            }
           
            Object[] keys  = map.keySet().toArray();
            // 길이가 긴 문자열부터 변환하기 위해 문자열 길이 내림차순으로 키를 정렬
            Arrays.sort(keys, new KeyOrderComparator());
           
            String srcLine = null;
            while ( (srcLine = brSrc.readLine()) != null ) {
                // 주석 라인은 skip
                if (!srcLine.trim().startsWith("//") &&
                    !srcLine.trim().startsWith("/*") &&
                    !srcLine.trim().startsWith("<!--")) {
                    for (int i = 0; i < keys.length; i++) {
                        if (srcLine.indexOf((String)keys[i]) > -1) {
                            srcLine = srcLine.replaceAll((String)keys[i],
                                    I18N_CODE_PREFIX + (String)map.get(keys[i]) + I18N_CODE_POSTFIX);
                        }
                    }
                }
               
                System.out.println(srcLine);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null)
                    br.close();
            } catch (Exception e) {}
           
            try {
                if (brSrc != null)
                    brSrc.close();
            } catch (Exception e) {}
        }
    }
}

class KeyOrderComparator implements Comparator {
    /**
     * 문자열의 길이에 따라 내림차순 정렬
     */
    public int compare(Object key1, Object key2) {
        return ((String)key2).length() - ((String)key1).length();
    }
}
[/code]
I18NReplace.java

[code]
데이터=data
[/code]
code.properties

[code xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" title="데이터">
...
</mx:TitleWindow>
[/code]
test.mxml


사용법이 복잡하진 않지만, 급하게 대강 만든 프로그램이라 GUI 등의 친절한 기능은 없다.

1. code.properties는 코드와 값을 넣은 건데 일반적인 순서와는 반대다.
이유는, 다국어 적용하기 전에 '데이터'라고 코딩을 했는데 이를 다국어 처리하기 위해서는
한글용 리소스번들 파일에 'data=데이터' 라는 내용이 있어야 한다.
그리고, '데이터' 대신에 다국어 처리 코드( Flex를 예로 들면, {resourceManager.getString('rb','data')} )를 넣으면
언어 설정에 따라 한국어일 때는 '데이터', 영어일 때는 'Data'라는 내용이 보이게 된다.
그런데, 지금 할 일이 '데이터'라고 하드코딩되어 있는 부분을 {resourceManager.getString('rb','data')}로 바꾸는 것이니까
code.properties 파일에는 '데이터=data' 즉, message=key 형태로 되어 있어야 한다.

2. test.mxml은 '데이터'라는 내용이 하드코딩되어 있는 소스 파일

3. I18N_CODE_PREFIX는 다국어처리코드에서 key 앞에 붙는 코드, I18N_CODE_POSTFIX는 key 뒤에 붙는 코드

참고로, 중간에 Arrays.sort 는 문자열길이에 따라 내림차순으로 정렬하는 건데,
그래야 '데이터 관리'라는 문자열이 소스에서 나왔을 때, '데이터 관리'라는 게 code.properties에 있을 때 우선적으로 처리하고
이게 없으면 '데이터'나 '관리'를 따로 변환하게 되어 원치 않는 결과가 나오게 된다.
이렇게 '데이터 관리'를 하나의 단어로 정의하는 것은 언어에 따라 어순이 바뀌거나,
두 단어 이상이 합쳐져서 만들어진 단어의 경우 언어에 따라 다른 의미가 될 수 있어서이다.

또, 참고로 파일을 읽을 때 "UTF-8"라는 설정이 있는데 이것은 "UTF-8" 인코딩으로 저장한 파일을 읽기 위해 사용한 것이다.
소스 파일이나 리소스번들 파일의 인코딩 형태에 따라 빼거나 고쳐서 사용하면 된다.


이렇게 설정한 상태에서 이 I18NReplace을 실행하면 치환된 결과가 표준출력으로 나오고,
이 결과를 원래 소스에 붙인 다음에 잘못 된 부분을 수정해서 저장하면 다국어 처리가 끝난다.

꼭 다국어 처리 변환에만 사용할 필요는 없고, 어떤 규칙에 따라 문자열을 치환해야 하는 경우 사용하면 되겠다.
당연한 얘기지만, code.properties 파일 정의시 띄어쓰기는 정확히 맞춰 주어야 한다.
AND

[code sql] SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD HH:MI SS') "NOW", TO_CHAR(SYSDATE+1, 'YYYY/MM/DD HH:MI SS') "1 DAY AFTER", TO_CHAR(SYSDATE+1/24, 'YYYY/MM/DD HH:MI SS') "1 HOUR AFTER", TO_CHAR(SYSDATE+1/24/60, 'YYYY/MM/DD HH:MI SS') "1 MINUTE AFTER", TO_CHAR(SYSDATE+1/24/60/60, 'YYYY/MM/DD HH:MI SS') "1 SECOND AFTER" FROM DUAL [/code]
당연히,
SYSDATE에 숫자를 더하면 현재시간 이후를 의미하고,
SYSDATE에서 숫자를 빼면 현재시간 이전을 의미

이런 쿼리를 사용하면 오라클이 아닌 다른 DB를 사용하게 되면
프로그램 고치는 일이 엄청나게 커지니까 오라클만 쓸 생각일 경우에만 사용해야 할 듯
시스템 운영자와 사이가 안 좋을 땐 이런 지뢰를 심어 놓는 방법이... ㅋㅋ

'Java_Web' 카테고리의 다른 글

HQL UNION 제약사항  (0) 2009.08.21
다국어 코드 적용하기  (0) 2009.03.02
Derby 사용하기  (2) 2008.09.29
자바에서 바이트 단위길이로 문자열 자르기  (0) 2008.07.01
ASM - 자바 바이트코드 분석하기  (1) 2008.03.07
AND

Derby 사용하기

Java_Web 2008. 9. 29. 18:03

가볍고 빠른 DB를 쓸 일이 있었는데 마침 딱 맞을 것 같아서 고른 Derby.

올해 초에 간단하게 써 보긴 했는데, 제대로 알고 쓰려고 하니 공부할 것이 꽤 많았다. 그래서, 열심히 삽질하면서 공부해서 필요한 걸 거의 3주만에 만들었는데, 그동안 공부한 것을 혹시 그냥 잊어 버리지 않을까 하는 마음에 정리도 할겸, 혹시 필요한 분들이 있으면 도움이 될까 해서 이렇게 글을 남겨 본다.

단, 여기서는 Embedded는 배제하고, Network Server를 중심으로 설명한다.


1. Derby

Derby는 관계형 데이터베이스의 하나로 맨 처음 IBMCloudscape라는 이름으로 WebSphere 등에서 사용하다가 Apache에 오픈소스로 공개되면서 Derby라는 이름을 갖게 되었다. 그후 Sun에서 JavaDB라는 이름을 붙여서 배포하게 되었고, JDK 6에 기본으로 포함되어 있다.

무료로 가볍고 간단하게 구성할 수 있으며 안정성이 높다. 다른 오픈소스 DB들에 비해 성능이 좀 떨어지지만 안정성이 우수하.


2. Derby의 연결방식

- Embedded 방식 : 하나의 JVM 내에 어플리케이션과 DB가 함께 존재하도록 구성하는 방식으로 다른 JVM이나 머신에서는 이 DB에 접근이 불가능하다.

- Network Server 방식 : 어플리케이션과 DB가 다른 JVM 또는 프로세스에 존재하도록 구성하는 방식으로 각 인스턴스가 하나의 JVM 내에서 동작하고, 일반적인 JDBC와 똑같은 방식으로 접근이 가능하다.

FISS의 경우, FISS_RULE을 비롯해 많은 커넥터들이 각기 다른 JVM으로 떠서 동작하고, 여기서 접근이 가능해야 하므로 Network Server 방식을 사용한다.

그러므로, 이하는 Network Server 방식을 기반으로 설명한다.

참고로, embedded 방식과 Network Server 방식은 JVM 외부에서의 접근가능여부와 Connection URL에서 IP가 들어가는 것 빼곤 사용방법이 동일하다.


3. Derby 인스턴스 기동

org.apache.derby.drda.NetworkServerControl 클래스를 실행시켜 기동(start), 정지(shutdown), (ping) 등의 작업을 수행할 수 있다.

java $JAVA_OPTION -classpath $CLASSPATH org.apache.derby.drda.NetworkServerControl start -p 54321 -h 192.168.1.123

-p 옵션은 인스턴스가 사용할 포트를 의미하며, 사용하지 않으면 Derbydefault 포트인 1527을 사용한다.

-h 옵션은 인스턴스가 요청을 받을 호스트를 나타내며, 호스트를 설정하면 그 외의 호스트명으로는 접근이 불가능하다. 제한을 두지 않으려면 이 옵션을 사용하지 않는다.


4. DB 연결 및 생성

사용자 계정을 이용한 연결기능도 지원하지만 여기서는 사용하지 않으므로 설명을 생략하고, 계정정보 없이 접속하면 defaultAPP라는 스키마를 사용한다. (계정정보를 이용해 접속하면 그 사용자 ID에 해당하는 스키마를 사용하게 된다.)

Derby는 특별히 DB를 생성하는 명령이 있지 않고, Connection URL의 끝에 “create=true”를 붙여 주었을 때 이 Connection URL에 해당하는 DB가 있으면 그냥 연결만 하고, 해당 DB가 존재하지 않으면 새롭게 생성한다. Connection URL에 “create=true”가 없을 때 해당 DB가 없으면 연결 오류가 발생한다.

DerbyJDBC 방식으로 연결하기 위한 Connection URL은 다음과 같다.


jdbc:derby://{IP}:{Port}/{DB생성디렉토리}/{DB};create=true

- IP : Derby Network Server가 떠 있는 머신의 IP를 나타내는데, 기동시 -h 옵션을 사용했다면 여기에 사용한 호스트명과 똑같이 입력해야 연결이 가능하다.

- Port : Derby Network Server기동할 때 -p 옵션을 사용했다면 여기서 사용한 포트번호를 입력한다. -p 옵션을 사용하지 않았다면 default 포트인 1527을 사용한다.

- DB생성디렉토리 : DB파일이 생성되는 디렉토리를 지정하고 싶으면 여기에 설정한다. , 디렉토리는 루트부터 시작하는 절대경로를 입력해야 하고, 그렇지 않으면 JVM을 실행하는 디렉토리의 하위디렉토리를 생성하고 거기에 DB파일을 생성한다. 루트부터 입력하므로 유닉스는 슬래쉬(/)2번 반복된다. 생략하면 JVM이 실행되는 디렉토리가 default이다.

- DB: DB명도 되고, DB데이터파일이 저장되는 디렉토리명도 된다. DB생성디렉토리를 설정했으면 그 하위에 디렉토리로 생기고, 그렇지 않으면 JVM이 실행된 디렉토리 아래에 생성된다.

- create=true : DB생성디렉토리에 해당 DB명이 있으면 상관없는데, 해당 DB명이 없으면 그 위치에 DB데이터 디렉토리를 자동으로 생성한다. 이 옵션을 사용하지 않으면 해당디렉토리에 해당 DB가 있으면 연결하고, 없으면 오류가 발생한다.


윈도우 예> jdbc:derby://localhost:1527/C:/derby/RULEDB1;create=true

UNIX > jdbc:derby://localhost:1527//usr/derby/RULEDB1;create=true


JDBC 방식의 연결은 DerbyJDBC Client 드라이버인 org.apache.derby.jdbc.ClientDriver를 로딩하고 위의 URL을 이용해서 DriverManager.getConnection을 호출하면 된다.


예제 코드>

Class.forName(org.apache.derby.jdbc.ClientDriver).newInstance();

DriverManager.getConnection(“jdbc:derby://localhost:1527/C:/derby/RULEDB1;create=true”);


그 밖에도 Derby에서 제공하는 DataSource도 이용 가능하다.


참고사항 : 하나의 인스턴스를 통해서 여러 DB에 접근할 수 있다. 하지만, 여러 인스턴스가 동시에 하나의 DB를 사용할 수는 없다. 그러므로, 어떤 DB를 어떤 인스턴스가 사용할지 명확하게 해 두어야 한다.

1527포트의 인스턴스를 통해 ruledb1ruledb2를 접근할 수는 있지만, 1527포트의 인스턴스와 1528포트의 인스턴스가 동시에 ruledb1이라는 DB를 접근할 수는 없다는 뜻이다.

※ Derby에 connection을 만들자 마자 autocommit을 false로 설정하는 것이 좋다. 그렇지 않으면, CUD 뿐만 아니라 R 처리에서도 부하가 가해지면 오류가 잔뜩 떨어지면서 문제가 발생한다. 하지만, autocommit을 false로 해 놓으면 꽤 많은 부하가 가해져도 오류없이 잘 처리해낸다. 단, 이렇게 되면 CUD는 무조건 commit, rollback을 해 줘야 한다.


5. 쿼리 수행

일반 JDBC동일하.


참고사항 : Derby에서 가장 빨리 수행될 수 있는 쿼리는 ‘SELECT 1 FROM SYSIBM.SYSDUMMY1’ 이다. SYSIBM.SYSDUMMY1 테이블은 오라클의 DUAL과 비슷한 기능이다.


- 오늘날짜 : SELECT CURRENT_DATE FROM SYSIBM.SYSDUMMY1 → 2008-09-29

- 현재시간 : SELECT CURRENT_TIME FROM SYSIBM.SYSDUMMY1 → 17:42:06

- 타임스탬프 : SELECT CURRENT_TIMESTAMP FROM SYSIBM.SYSDUMMY1 → 2008-09-29 17:42:13.328

시간이나 날짜를 문자열로 포맷팅하는 함수는 제공하지 않는 것 같다. 아마도 위에서 나오는 문자열을 substring으로 잘라서 쓰거나, 원래의 데이터타입을 이용해 setDategetDate를 이용해야 할 것 같다.


6. ij (Derby용 유틸리티 프로그램) 사용

DerbyNetwork Server로 기동시키면 EclipseData Source Explorer로 접속도 가능하고, Derby와 함께 제공되는 ij라는 유틸리티로도 접근이 가능하다.

- ij 실행

명령프롬프트에서 $DERBY_HOME/binij 를 실행한다.

C:\derby\bin> ij

- DB 연결

connect 명령과 connection URL을 이용해서 DB에 연결한다.

ij> connect 'jdbc:derby://localhost:1527/C:/derby/RULEDB1';

- ij 명령어 보기

ij> help;

- 스키마 목록 보기

ij> show schemas;

- 현재 연결된 DB들에 대한 연결정보 보기

ij> show connections;

- 테이블 리스트 보기

ij> show tables;

- 테이블 구조 보기

ij> describe {테이블명};

- ij 끝내기

ij> exit;

- 그 밖에 모든 DDL, DML 수행 가능하며, 끝은 반드시 세미콜론(;)으로 끝나고 엔터를 쳐야 실행된다.




Derby를 이용해서 프로그램을 다 만든 다음에 용도에 딱 맞는 프로그램을 하나 찾았다.

Memcached(멤캐쉬디)라고 아마도 Memory Cache Daemon의 줄임말이 아닐까 생각이 된다.

웹페이지 로딩을 빠르게 하기 위해 만들어졌다고 본 것 같은데,

키와 Object의 pair로 저장이 되고, 정해진 메모리양을 넘어가면 LRU 방식으로 비워 가면서 정보를 추가한다.

데몬을 띄울 때 메모리의 양을 할당하는 옵션이 있고,

2개 이상의 동일한 내용을 담을 데몬을 띄워 놓을 수 있는데

클라이언트 객체를 만들 때 이들 데몬의 호스트명과 포트명을 한꺼번에 주면

데몬 하나가 죽을 때 다른 살아있는 데몬에 읽고 쓸 수 있기 때문에 장애에 대한 대처도 가능하다.

단, 소스가 C로 작성되어 있어서 실행하려면 OS에 따라 컴파일해서 사용해야 한다.

유명한 OS(윈도우 포함)인 경우는 컴파일해서 올려 놓은 프로그램을 다운받아서 사용해도 된다.

클라이언트는 다양한 언어로 구현된 것이 올라와 있기 때문에 골라서 사용하면 된다.

나는 윈도우용으로 컴파일된 프로그램을 설치하고 띄운 후에,

자바 클라이언트로 접속해서 사용해 봤는데 잘 작동했고 성능도 괜찮았던 것 같았다.

(몇 달 만에 기억을 더듬으며 쓰려니 가물가물하넹.)

참, 이것도 오픈소스이다.

참고로 테스트용으로 사용한 자바 소스파일 첨부했으니 참고하시길...

여러 데몬에 한꺼번에 연결하려면 아래와 같이 고치면 됨.

MemcachedClient c = new MemcachedClient(AddrUtil.getAddresses("server1:11211 server2:11211"));



자세한 내용은 아래의 홈페이지 참조 요망~

www.danga.com/memcached/


자바 클라이언트 download 및 설명

http://code.google.com/p/spymemcached/




AND

모 이런 거 어딘가 있다는 얘길 들었는데, 내가 만들면 더 잘 할 수 있을 거 같아서 한번 만들어 봤다.
하다가 귀찮아져서 겨우 문제 없이 돌아가는 수준에서 멈췄으니 고쳐 쓸 사람은 얼마든지 고쳐서 쓰시길...

용도는 아무래도 바이트 단위의 길이로 정의된 DB 컬럼에 데이타를 넣을 때,
어쩔 수 없이 잘라서 넣어야 하는 경우가 생기는데 이럴 때 이 메소드 한방으로 해결.
바이트 단위라는 부분에서 냄새를 맡았겠지만, 한글을 비롯한 한글자가 2바이트 이상을 사용할 때에 유용하겠다.
오라클 같은 경우 VARCHAR2 길이가 4000바이트 밖에 안 되다 보니 긴 내용을 넣기에 좀 부족한 느낌이 있는데,
그렇다고 LONG이나 CLOB를 쓰는 건 성능도 안 좋고, 다루기도 불편하니
이런 식으로 잘라서 VARCHAR2 컬럼에 넣는 방법을 종종 사용한다고 한다.

첫번째 메소드는 원하는 바이트수만큼만으로 이루어진 String 리턴
getMaxByteString(str, 400) 을 호출하면 str이라는 문자열에서 앞에서 최대 400바이트만큼 잘라서 문자열으로 만들어 리턴
즉, 리턴한 문자열을 보면 str이 400바이트 이상이면 399바이트 아니면 400바이트이겠고, 그보다 짧으면 통째로 리턴할 것이다.
[code java] // str이라는 문자열의 맨앞부터 최대 maxLen만큼의 바이트수로 이루어진 문자열을 잘라서 리턴 public static StringgetMaxByteString(String str, int maxLen) { StringBuilder sb = new StringBuilder(); int curLen = 0; String curChar; for (int i = 0; i < str.length(); i++) { curChar = str.substring(i, i+1); curLen += curChar.getBytes().length; if (curLen > maxLen) break; else sb.append(curChar); } return sb.toString(); } [/code]
두번 째 메소드는 원하는 바이트수(maxLen)만큼만으로 이루어진 String 배열을 str 문자열 끝까지 처리해서 리턴
getMaxByteStringArray(str, 400) 을 호출하면 str이라는 문자열에서 앞에서 최대 400바이트만큼 잘라서 문자열로 만들고
그 후에 문자열이 또 있으면 또 이어서 최대 400바이트만큼 잘라서 문자열을 만들고. 이걸 문자열 끝까지...
만들어진 문자열을 배열로 만들어서 리턴
별도 테이블을 만들어서 각 문자열을 하나의 로우에 저장하도록 구성한다면 이것도 괜찮을 듯.
[code java] // str이라는 문자열의 맨앞부터 끝까지 최대 maxLen만큼의 바이트수로 이루어진 문자열을 // 연속으로 잘라서 String 배열로 리턴 public static String[]getMaxByteStringArray(String str, int maxLen) { return getMaxByteStringArray(str, maxLen, -1); } [/code]
세번째 메소드는 원하는 바이트수(maxLen)만큼만으로 이루어진 String 배열을 최대 maxArrays만큼 길이로 리턴
getMaxByteStringArray(str, 400, 3) 을 호출하면 str이라는 문자열에서 앞에서 최대 400바이트만큼 잘라서 문자열로 만들고
그 후에 문자열이 또 있으면 또 이어서 최대 400바이트만큼 잘라서 문자열을 만들고. 이걸 문자열을 최대 3번까지...
만들어진 문자열을 배열로 만들어서 리턴
한 테이블의 3개의 컬럼에 문자열을 쪼개서 저장한다면 유용할 듯.
[code java] // str이라는 문자열의 맨앞부터 최대 maxLen만큼의 바이트수로 이루어진 문자열을 // 연속으로 잘라서 최대 maxArrays 길이의 배열로 리턴 public static String[]getMaxByteStringArray(String str, int maxLen, int maxArrays) { StringBuilder sb = new StringBuilder(); ArrayList strList = new ArrayList(); int curLen = 0; String curChar; for (int i = 0; i < str.length(); i++) { curChar = str.substring(i, i+1); curLen += curChar.getBytes().length; if (curLen > maxLen) { if (maxArrays == -1 || strList.size() <= maxArrays-2) { strList.add(sb.toString()); sb = new StringBuilder(); curLen = 0; i--; } else break; } else sb.append(curChar); } strList.add(sb.toString()); String[] strArr = new String[strList.size()]; for (int i = 0; i < strList.size(); i++) { strArr[i] = strList.get(i); } return strArr; } [/code]
아래는 위의 메소드를 호출하는 샘플 코드
이 코드 돌려 보고 싶으면, 위의 메소드들과 아래의 main 메소드 합쳐서 한 클래스에 넣고 돌리면 된다.
[code java] public static void main(String[] args) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append("codePointAt을 사용하면 문자의 유니코드값을 구할 수 있잖아요.. 근데.. 문자의 유니코드값을 다시 문자로 변환해"); } Stringstr = sb.toString(); String newStr = getMaxByteString(str, 4000); System.out.println(newStr + ":" + newStr.getBytes().length); System.out.println("-----------------------------------------"); String[] strArr = getMaxByteStringArray(str, 4000); for (int i = 0; i < strArr.length; i++) { System.out.println(strArr[i] + ":" + strArr[i].getBytes().length); } System.out.println("-----------------------------------------"); String[] strArr2 = getMaxByteStringArray(str, 4000, 3); for (int i = 0; i < strArr2.length; i++) { System.out.println(strArr2[i] + ":" + strArr2[i].getBytes().length); } } [/code]
한 글자씩 잘라 붙이기라서 오래 걸릴 줄 알았는데, 꽤 긴 문자열도 0.1초 이내에 잘라 내니 쓸 만하군...

'Java_Web' 카테고리의 다른 글

오라클에서 SYSDATE를 이용한 시간 연산  (0) 2009.02.12
Derby 사용하기  (2) 2008.09.29
ASM - 자바 바이트코드 분석하기  (1) 2008.03.07
클래스 위치 찾아 주는 프로그램  (0) 2007.08.15
놀라운 발견  (0) 2007.08.12
AND