11.LiteDB

Edit

11.1LiteDBConnection / LiteDBStatement 소개

LiteDBConnection, LiteDBStatement는 데이터베이스를 연결하고 쿼리를 수행하여 데이터를 조작할 수 있게 해주는 오브젝트입니다. 오브젝트 이름에서 알 수 있듯이 경량 데이터베이스 엔진인 SQLite를 연결해 사용할 수 있으며 사용자에게 SQLite를 조작할 수 있는 API를 제공합니다.

SQLite는 별도의 서버가 필요 없는 파일 기반의 DBMS로 애플리케이션에 임베딩하여 라이브러리 형태로 사용합니다. SQLite에 대한 자세한 정보는 https://www.sqlite.org를 참조하십시오.

본 장의 샘플에서는 nexacro_sample_db.sqlite 파일을 사용합니다. 이 파일은 사전에 데이터를 입력해 놓은 SQLite 파일로서 TB_DEPT, TB_POS, TB_EMP 세 개의 테이블로 구성되어 있습니다. 각 테이블은 다음과 같은 구조를 갖습니다.

그림 11-1SQLite_TB_DEPT

사용자가 직접 SQLite 데이터베이스 파일의 내용을 확인하거나 수정하려면 SQLite에서 기본적으로 제공하는 SQLite command-line tool이나 DB Browser for SQLite와 같은 애플리케이션을 사용해야 합니다.

11.2SQLite 데이터베이스 생성하기

SQLite 프로젝트에서는 데이터베이스 엔진과 더불어 간단히 사용할 수 있는 커맨드 라인 기반의 툴을 제공합니다. 사용자는 커맨드를 입력하여 데이터베이스를 생성, 설정하고 SQL문을 수행하여 데이터베이스를 조작할 수 있습니다.

이 절에서는 커맨드 라인 툴로 예제에서 사용할 SQLite 데이터베이스를 만드는 방법을 설명합니다.

SQLite 커맨드 라인 툴은 사용자가 모든 명령을 직접 입력해야 하고 결과물을 확인할 수 있는 UI 인터페이스를 제공하지 않습니다. 만일 사용이 불편하다면 DB Browser for SQLite와 같이 UI를 제공하는 애플리케이션을 사용해도 같은 결과를 얻을 수 있습니다.

11.2.1SQLite 커맨드 라인 툴 설치하기

SQLite 커맨드 라인 툴은 SQLite Download에서 사용자 환경에 맞는 버전('sqlite-tools-'로 시작하는 압축 파일)을 내려받을 수 있습니다. 파일을 내려받은 후 적당한 디렉터리에 압축을 해제하면 exe 형태의 실행 파일이 나옵니다.

sqlite3.exe

데이터베이스를 생성, SQL 문을 수행하여 데이터 베이스 관리

sqlite3_analyzer.exe

데이터베이스 파일을 분석

sqldiff.exe

데이터베이스 파일 비교

이 파일들은 별도의 설치 과정없이 바로 실행이 가능한 프로그램입니다. 여기서는 sqlite3.exe만을 사용합니다.

11.2.2데이터베이스 파일 생성하기

데이터베이스 파일을 생성하려면 sqlite3.exe를 사용합니다. 사용법은 다음과 같이 생성할 데이터베이스 파일명만 입력하면 됩니다. 데이터베이스 파일의 확장자는 어떤 것을 사용해도 무방하나 일반적으로 db, db3, sqlite 등을 사용합니다.

sqlite3.exe [DB 파일]

sqlite3.exe 파일이 위치한 경로로 이동 후 커맨드 프롬프트에서 'sqlite3.exe nexacro_sample_db.sqlite' 라고 입력합니다. 만일 해당 경로에 같은 파일이 존재하면 파일을 새로 생성하지 않고 기존 파일을 오픈합니다. '.databases' 명령어로 현재 오픈된 데이터베이스 파일을 확인할 수 있습니다.

sqlite3.exe 실행 후 다른 데이터베이스 파일을 생성 혹은 오픈하려면 '.open' 커맨드를 사용합니다.

sqlite> .open [DB 파일]

11.2.3테이블 생성하기

데이터베이스 파일을 생성했으므로 이제 테이블을 생성합니다. 커맨드 프롬프트에 다음과 같이 SQL 문을 입력하여 테이블을 생성합니다. 생성하는 테이블은 TB_POS(직책 정보), TB_EMP(직원 정보), TB_DEPT(부서 정보)와 같으며 다음에서 스키마를 확인할 수 있습니다.

/* TB_POS Table */
CREATE TABLE IF NOT EXISTS `TB_POS` (
    `POS_CD`    VARCHAR2 ( 2 ),
    `POS_NAME`    VARCHAR2 ( 50 )
);
/* TB_EMP Table */
CREATE TABLE IF NOT EXISTS `TB_EMP` (
    `EMPL_ID`    VARCHAR2 ( 5 ),
    `FULL_NAME`    VARCHAR2 ( 50 ) DEFAULT (null),
    `DEPT_CD`    VARCHAR2 ( 2 ) DEFAULT (null),
    `POS_CD`    VARCHAR2 ( 2 ),
    `HIRE_DATE`    VARCHAR2 ( 8 ),
    `GENDER`    VARCHAR2 ( 1 ),
    `MARRIED`    BOOLEAN ( 1 ),
    `SALARY`    INTEGER ( 12 ),
    `MEMO`    TEXT
);
/* TB_DEPT Table */
CREATE TABLE IF NOT EXISTS `TB_DEPT` (
    `DEPT_CD`    VARCHAR2 ( 2 ) DEFAULT (NULL),
    `DEPT_NAME`    VARCHAR2 ( 50 ) DEFAULT (NULL)
);

SQL문 수행이 완료된 후 테이블이 정상적으로 생성됐는지 '.tables' 명령어로 확인합니다.

11.2.4데이터 입력하기

테이블을 생성했으면 이제 실제 데이터를 입력합니다. 커맨드 프롬프트에서 다음과 같이 SQL 문으로 각 테이블에 데이터를 입력합니다.

/* TB_POS Table */
INSERT INTO `TB_POS` VALUES ('07','Officer');
INSERT INTO `TB_POS` VALUES ('06','Supervisor');
INSERT INTO `TB_POS` VALUES ('05','Assistant Manager');
INSERT INTO `TB_POS` VALUES ('04','Department Manager');
INSERT INTO `TB_POS` VALUES ('03','Division Manager');
INSERT INTO `TB_POS` VALUES ('02','President');
INSERT INTO `TB_POS` VALUES ('01','Chairman');
/* TB_EMP Table */
INSERT INTO `TB_EMP` VALUES ('AA001','Oleg','08','03','20072504','W',1,70000,'green');
INSERT INTO `TB_EMP` VALUES ('AA010','Aladdin','07','06','20041909','M',0,120000,'green');
INSERT INTO `TB_EMP` VALUES ('BB010','Curran','02','03','20070111','M',1,210000,'orange');
INSERT INTO `TB_EMP` VALUES ('BB020','Adam','07','07','20011602','W',1,90000,'indigo');
INSERT INTO `TB_EMP` VALUES ('BB030','Heather','03','03','20061406','M',0,50000,'blue');
INSERT INTO `TB_EMP` VALUES ('CC110','Lester','07','05','20171604','M',0,100000,'green');
INSERT INTO `TB_EMP` VALUES ('CD120','Elijah','10','01','20151304','W',0,110000,'gold');
INSERT INTO `TB_EMP` VALUES ('AB100','Angela','08','04','20021110','M',1,670000,'blue');
INSERT INTO `TB_EMP` VALUES ('AC310','Rae','02','05','20072603','W',1,90000,'green');
INSERT INTO `TB_EMP` VALUES ('AC210','Denton','02','04','20172503','M',1,90000,'skyblue');
INSERT INTO `TB_EMP` VALUES ('DD002','Nora','05','01','20160202','W',0,420000,'blue');
INSERT INTO `TB_EMP` VALUES ('DD200','Adrian','05','04','20160212','W',0,80000,'violet');
INSERT INTO `TB_EMP` VALUES ('AD020','Ulric','04','04','20042107','W',0,420000,'yellow');
INSERT INTO `TB_EMP` VALUES ('BD030','Veronica','10','06','20130701','M',1,70000,'green');
INSERT INTO `TB_EMP` VALUES ('AA200','Phyllis','02','06','20120812','W',1,350000,'orange');
/* TB_DEPT Table */
INSERT INTO `TB_DEPT` VALUES ('01','Accounting Team');
INSERT INTO `TB_DEPT` VALUES ('02','Finances Team');
INSERT INTO `TB_DEPT` VALUES ('03','Human Resource Team');
INSERT INTO `TB_DEPT` VALUES ('04','Marketing Team');
INSERT INTO `TB_DEPT` VALUES ('05','Sales Team');
INSERT INTO `TB_DEPT` VALUES ('06','Consulting  Team');
INSERT INTO `TB_DEPT` VALUES ('07','Design Team');
INSERT INTO `TB_DEPT` VALUES ('08','Mobile Team');
INSERT INTO `TB_DEPT` VALUES ('09','Education Team');
INSERT INTO `TB_DEPT` VALUES ('10','Technical Support Team');
INSERT INTO `TB_DEPT` VALUES ('11','Customer Support Team');

데이터 입력 후 SQL 문을 사용해 각 테이블에 입력된 데이터를 확인할 수 있습니다.

데이터 입력 및 확인을 완료하면 '.exit' 명령으로 프로그램을 종료합니다. 생성된 nexacro_sample_db.sqlite 파일은 별다른 처리없이 LiteDB 오브젝트에 연결해 사용이 가능합니다.

11.3데이터베이스 연결/종료하기

애플리케이션에서 데이터베이스를 연결, 종료할 때는 LiteDBConnection 오브젝트를 사용합니다. async, busytimeout, datasource, openflag, preconnect 등의 속성을 설정하면 데이터베이스 연결시 옵션을 설정할 수 있습니다.

11.3.1예제

다음은 데이터베이스에 연결하고 데이터베이스의 특정 테이블을 조회하여 Grid로 출력하는 예제입니다.

Open 버튼을 터치하면 데이터베이스로 연결이 설정되고 TB_EMP 테이블을 조회하여 데이터를 Grid로 출력해줍니다. Close 버튼을 터치하면 데이터베이스로의 연결이 종료됩니다.

nexacro_sample_db.sqlite 파일은 사전에 작성한 SQLite 데이터베이스 파일입니다. 생성 방법은 SQLite 데이터베이스 생성하기를 참조하십시오.

그림 11-2sample_litedb_01

11.3.2예제에서 사용한 핵심 기능

LiteDBConnection > open 메소드

데이터베이스를 연결하는 메소드입니다. 첫 번째 인자로 SQLite 파일의 위치와 파일명을 입력하고, 두 번째 인자로 데이터베이스를 어떻게 오픈할지 설정합니다.

LiteDBConnection > datasource 속성

연결할 데이터베이스의 위치 정보를 설정하는 속성입니다. 데이터베이스 경로와 파일명을 같이 입력합니다.

LiteDBConnection > close 메소드

데이터베이스 연결을 닫는 메소드입니다.

LiteDBConnection > isConnected 메소드

데이터베이스가 연결되어 있는지 확인하는 메소드입니다.

LiteDBErrorEventInfo 오브젝트

LiteDBConnection, LiteDBStatement 오브젝트의 수행에 오류가 생겼을 때 onerror 이벤트 함수로 전달되는 EventInfo 오브젝트입니다. 어떤 에러가 발생했는지 확인하여 예외 처리를 할 수 있습니다.

LiteDBEventInfo 오브젝트

LiteDBConnection, LiteDBStatement 오브젝트의 작업 수행이 성공했을 때 onsuccess 이벤트 함수로 전달되는 EventInfo 오브젝트입니다. 이벤트 발생 원인에 대한 정보와 작업 수행 결과값을 갖습니다.

11.3.3예제 구현 방법

1

화면 구성하기

LiteDBConnection, LiteDBStatement 오브젝트를 추가합니다. 추가된 오브젝트는 Invisible Object 창에서 확인할 수 있습니다.

데이터베이스 파일 경로를 입력 혹은 표시할 Edit 컴포넌트와 사용자로부터 수행을 명령을 받기 위한 Button 컴포넌트를 예제의 그림과 같이 적절히 배치합니다. 추가로 오픈한 데이터베이스로부터 데이터를 받아 화면에 출력할 Grid 컴포넌트와 Dataset 오브젝트도 추가합니다.

화면 구성을 위해 사용한 컴포넌트 및 오브젝트는 다음과 같습니다.

컴포넌트/오브젝트

ID

LiteDBConnection

LiteDBConnection00

LiteDBStatement

LiteDBStatement00

Dataset

Dataset00

Grid

Grid00

GroupBox

GroupBox00

Edit

edt_dbfile

Button

btn_dbopen

btn_dbclose

2

Edit 컴포넌트 설정하기

추가한 Edit 컴포넌트의 value 속성을 '%USERAPP%File/nexacro_edu_db.sqlite'로 설정합니다. 이 파일은 SQLite 파일로 프로젝트와 함께 샘플로 제공된 파일로 넥사크로 스튜디오의 Project Explorer에서 File 디렉터리에서 확인할 수 있습니다.

3

Open 버튼 이벤트 함수 작성하기

/* Open 버튼 onclick 이벤트 함수 */
this.btn_dbopen_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBConnection00.isConnected();
};

4

Close 버튼 이벤트 함수 작성하기

/* Close 버튼 onclick 이벤트 함수 */
this.btn_dbclose_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBConnection00.close();
};

5

LiteDBConnection 이벤트 함수 작성하기

데이터베이스 연결, 연결 체크, 종료 작업이 성공했을 때 수행할 onsuccess 이벤트 함수를 작성합니다. e.reason 속성 값을 통해 어떤 메소드를 호출했는지 확인할 수 있습니다.

/* LiteDBConnection 오브젝트 onsuccess 이벤트 함수 */
this.LiteDBConnection00_onsuccess = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBEventInfo)
{
    switch(e.reason)
    {
        case 2:    // LiteDBConnection close()
            this.Grid00.set_visible(false);
            alert("DB close succeed.");
            break;
        case 4: // LiteDBConnection isConnected()
            alert("Already connected to DB.");
            break;
        case 5: // LiteDBConnection open()
            this.Grid00.set_visible(true);
            
            this.LiteDBStatement00.set_ldbconnection(this.LiteDBConnection00);
            this.LiteDBStatement00.executeQuery("select * from tb_emp");
            break;        
        case 1:    // LiteDBConnection begin()
        case 3: // LiteDBConnection commit()
        case 6:    // LiteDBConnection rollback()
        default:
            break;
    }
};

데이터베이스 연결, 연결 체크, 종료 작업이 실패했을 때 수행할 onerror 이벤트 함수를 작성합니다. e.statuscode 속성 값을 통해 어떤 메소드 수행시 에러가 발생했는지 확인할 수 있습니다.

/* LiteDBConnection 오브젝트 onerror 이벤트 함수 */
this.LiteDBConnection00_onerror = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBErrorEventInfo)
{    
    switch(e.statuscode.toString())
    {
        case "1203":    //LiteDBConnection close() error
            alert("DB close failed.");
            break;
        case "1205":    //LiteDBConnection isConnected() error
            //alert("DB is not connected.");        
            this.LiteDBConnection00.set_datasource(this.edt_dbfile.value);
            this.LiteDBConnection00.open();        
            break;
        case "1206":    //LiteDBConnection open() error
            alert("DB open failed.");
            break;    
        case "00001":    //Parameter setting error
        case "1201":    //DB response timeout error
        case "1202":    //LiteDBConnection begin() error
        case "1204":    //LiteDBConnection commit() error            
        case "1207":    //LiteDBConnection rollback() error
        default:        //Unknown error        
            var strResult = "[LiteDBConnection00_onerror]";    
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;
            alert(strResult);                
    }    
};

6

LiteDBStatement 이벤트 함수 작성하기

연결된 데이터베이스에 쿼리 수행이 성공하면 발생할 onsuccess 이벤트 함수를 작성합니다. 쿼리문의 결과 값으로 받은 데이터를 Dataset으로 받아 Grid로 출력합니다.

/* LiteDBStatement 오브젝트 onsuccess 이벤트 함수 */
this.LiteDBStatement00_onsuccess = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBEventInfo)
{        
    this.Dataset00.copyData(e.returnvalue);        
    this.Grid00.createFormat();
};

연결된 데이터베이스에 대한 쿼리 수행이 실패하면 발생할 onerror 이벤트 함수를 작성합니다.

/* LiteDBStatement 오브젝트 onerror 이벤트 함수 */
this.LiteDBStatement00_onerror = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBErrorEventInfo)
{
    switch(e.statuscode.toString())
    {
        case "1210":    //LiteDBStatement executeQuery() error
            alert("LiteDBStatement executeQuery() error");
            break;
        case "1211":    //LiteDBStatement executeUpdate() error
            alert("LiteDBStatement executeUpdate() error");
            break;
        case "00001":    //Parameter setting error
        case "1201":    //DB response timeout error
        default:        //Unknown error
            var strResult = "[LiteDBStatement00_onerror]";
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;
            alert(strResult);    
    }    
};

7

모바일 장치에서 확인하기

Open 버튼을 터치하여 데이터베이스 연결이 수행되는지 확인합니다. 정상적으로 연결이 수행되면 Grid에 TB_EMP 테이블의 데이터가 출력됩니다.

데이터베이스 연결을 닫으려면 Close 버튼을 터치합니다. 정상적으로 데이터베이스가 닫히면 Grid가 사라집니다.

11.4쿼리 수행하기

LiteDBStatement는 DB 연결 후 쿼리를 수행할 때 사용하는 오브젝트입니다. LiteDBStatement 오브젝트는 쿼리를 수행하는 executeQuery, executeUpdate 메소드와 수행중인 쿼리를 중단하는 close 메소드를 제공합니다. 쿼리를 수행하는 메소드는 쿼리문의 종류에 따라 Select 문은 executeQuery 메소드를 사용하고 Insert, Update, Delete 문은 executeUpdate 메소드를 사용합니다.

11.4.1예제

다음은 데이터베이스에 연결하고 쿼리문을 수행한 결과를 Grid로 출력하는 예제입니다.

화면이 로딩되면 자동으로 데이터베이스 연결을 수행하며 TB_POS 테이블을 조회하여 데이터를 Grid로 출력합니다. 데이터베이스 연결이 완료되면 쿼리문을 선택하고 Query 버튼을 터치합니다. 쿼리가 수행된 결과는 즉시 Grid로 반영됩니다. 쿼리 수행중에 Stop 버튼을 터치하면 수행이 중단됩니다.

그림 11-3example_litedb_02

11.4.2예제에서 사용한 핵심 기능

LiteDBStatement > ldbconnection 속성

데이터베이스와 연결된 LiteDBConnection 오브젝트를 LiteDBStatement 오브젝트로 연결해주는 속성입니다. 정상적으로 속성 설정이 완료되어야 쿼리문을 수행할 수 있습니다.

LiteDBStatement > query 속성

쿼리문을 설정하는 속성입니다. executeQuery, executeUpdate 메소드 호출시 쿼리문을 인수로 입력하지 않으면 이 속성에 설정된 값이 쿼리문으로 사용됩니다.

LiteDBStatement > executeQuery 메소드

select 쿼리를 수행하는 메소드입니다. 인수를 입력하지 않으면 query 속성에 설정된 값이 쿼리문으로 사용됩니다.

LiteDBStatement > executeUpdate 메소드

insert, update, delete 쿼리를 수행하는 메소드입니다. 인수를 입력하지 않으면 query 속성에 설정된 값이 쿼리문으로 사용됩니다.

LiteDBStatement > close 메소드

쿼리 수행을 중단하는 메소드입니다.

11.4.3예제 구현 방법

1

화면 구성하기

LiteDBConnection, LiteDBStatement 오브젝트를 추가합니다. 추가된 오브젝트는 Invisible Object 창에서 확인할 수 있습니다.

데이터베이스 파일 경로를 입력 혹은 표시할 Edit 컴포넌트와 사용자로부터 수행 명령을 받기 위한 ExtCombo, Button 컴포넌트를 예제의 그림과 같이 적절히 배치합니다. 추가로 정상적으로 데이터베이스가 오픈됐는지 확인하기 위한 Grid 컴포넌트와 Dataset 오브젝트도 추가합니다.

화면 구성을 위해 사용한 컴포넌트 및 오브젝트는 다음과 같습니다.

컴포넌트/오브젝트

ID

LiteDBConnection

LiteDBConnection00

LiteDBStatement

LiteDBStatement00

Dataset

Dataset00

Grid

Grid00

GroupBox

GroupBox00

GroupBox01

Edit

edt_dbfile

ExtCombo

ExtCombo00

Button

btn_query

btn_stop

2

Database 그룹의 Edit 컴포넌트 설정하기

추가한 Edit 컴포넌트의 value 속성을 '%USERAPP%File/nexacro_edu_db.sqlite'로 설정합니다. 이 파일은 SQLite 파일로 프로젝트와 함께 샘플로 제공된 파일로 넥사크로 스튜디오의 Project Explorer에서 File 디렉터리에서 확인할 수 있습니다.

3

Form 이벤트 함수 작성하기

폼 로딩 후 데이터베이스가 연결되어 있는지 확인할 onload 이벤트 함수를 작성합니다.

/* Form의 onload 이벤트 함수 */
this.sample_litedb_02_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo)
{
    this.LiteDBConnection00.isConnected();
};

4

LiteDBConnection 이벤트 함수 작성하기

데이터베이스 연결, 연결 체크, 종료 작업이 성공했을 때 수행할 onsuccess 이벤트 함수를 작성합니다. e.reason 속성 값을 통해 어떤 메소드를 호출했는지 확인할 수 있습니다.

this.LiteDBConnection00_onsuccess = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBEventInfo)
{
    switch(e.reason)
    {
        case 2:    // LiteDBConnection close()
            this.Grid00.set_visible(false);
            this.btn_query.set_enable(false);
            break;
        case 4: // LiteDBConnection isConnected()
            alert("Already connected to DB.");
            break;
        case 5: // LiteDBConnection open()
            this.Grid00.set_visible(true);
            this.btn_query.set_enable(true);

            this.LiteDBStatement00.set_ldbconnection(this.LiteDBConnection00);
            this.LiteDBStatement00.executeQuery("select * from tb_pos");
            break;                    
        case 1:    // LiteDBConnection begin()
        case 3: // LiteDBConnection commit()
        case 6:    // LiteDBConnection rollback()
        default:
            break;
    }
};

데이터베이스 연결, 연결 체크, 종료 작업이 실패했을 때 수행할 onerror 이벤트 함수를 작성합니다. e.statuscode 속성 값을 통해 어떤 메소드 수행시 에러가 발생했는지 확인할 수 있습니다.

this.LiteDBConnection00_onerror = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBErrorEventInfo)
{    
    switch(e.statuscode.toString())
    {
        case "1203":    //LiteDBConnection close() error
            alert("DB close failed.");
            break;
        case "1205":    //LiteDBConnection isConnected() error
            this.LiteDBConnection00.set_datasource(this.edt_dbfile.value);
            this.LiteDBConnection00.open();                
            break;
        case "1206":    //LiteDBConnection open() error
            alert("DB open failed.");
            break;            
        case "00001":    //Parameter setting error
        case "1201":    //DB response timeout error
        case "1202":    //LiteDBConnection begin() error
        case "1204":    //LiteDBConnection commit() error            
        case "1207":    //LiteDBConnection rollback() error
        default:        //Unknown error        
            var strResult = "[LiteDBConnection00_onerror]";    
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;            
            alert(strResult);                
    }    
};

5

LiteDBStatement 이벤트 함수 작성하기

쿼리 수행이 성공했을 때 수행할 onsuccess 이벤트 함수를 작성합니다. e.reason 속성 값을 통해 어떤 메소드를 호출했는지 확인할 수 있습니다.

/* LiteDBStatement 오브젝트 onsuccess 이벤트 함수 */
this.LiteDBStatement00_onsuccess = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBEventInfo)
{    
    switch(e.reason)
    {
        case 7:    // LiteDBStatement executeQuery()
            this.Dataset00.copyData(e.returnvalue);
            this.Dataset00.set_keystring("S:+POS_CD+POS_NAME");
            this.Grid00.createFormat();        
            break;
        case 8:    // LiteDBStatement executeUpdate()
            this.LiteDBStatement00.set_query("select * from tb_pos");
            this.LiteDBStatement00.executeQuery();
            break;
        case 9:    // LiteDBStatement close()
        default:
            break;
    }    
};

쿼리 수행이 실패했을 때 수행할 onerror 이벤트 함수를 작성합니다. e.statuscode 속성 값을 통해 어떤 메소드 수행시 에러가 발생했는지 확인할 수 있습니다.

/* LiteDBStatement 오브젝트 onerror 이벤트 함수 */
this.LiteDBStatement00_onerror = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBErrorEventInfo)
{
    switch(e.statuscode.toString())
    {
        case "1210":    //LiteDBStatement executeQuery() error
            alert("LiteDBStatement executeQuery() error.");
            break;
        case "1211":    //LiteDBStatement executeUpdate() error
            alert("LiteDBStatement executeUpdate() error.");
            break;        
        case "00001":    //Parameter setting error
        case "1201":    //DB response timeout error
        default:        //Unknown error        
            var strResult = "[LiteDBStatement00_onerror]";    
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;            
            alert(strResult);
    }
};

6

Query 그룹의 ExtCombo 설정하기

ExtCombo 컴포넌트의 innerdataset 속성에서 편집기를 오픈하여 innerdataset을 설정합니다. 예제에서 사용할 SQL 쿼리문을 다음과 같이 입력합니다.

그림 11-4example_litedb_02_01

ExtCombo 컴포넌트의 속성을 다음과 같이 설정합니다. innerdataset을 바인딩 해주고 ExtCombo 클릭시 오픈될 팝업 윈도우 폼을 popupurl 속성에 설정합니다.

속성

popupurl

Base::pExtCombo.xfdl

innerdataset

innerdataset

codecolumn

codecolumn

datacolumn

datacolumn

7

Query 그룹의 Query 버튼 이벤트 함수 작성하기

사용자로부터 입력받은 문자열을 보고 어떤 쿼리문인지 판단하여 select면 executeQuery 메소드를 호출하고, insert, update, delete면 executeUpdate 메소드를 호출합니다.

/* Query 버튼 onclick 이벤트 함수 */
this.btn_query_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBStatement00.set_query(this.ExtCombo00.text);
    
    var arrString = this.LiteDBStatement00.query.split(" ");    
    
    switch(arrString[0])
    {
        case "select":
            this.LiteDBStatement00.executeQuery();
            break;
        case "insert":
        case "update":
        case "delete":
            this.LiteDBStatement00.executeUpdate();
            break;
        default:
            alert(arrString[0] + " is illegal query statement.");
    }
};

8

Query 그룹의 Stop 버튼 이벤트 함수 작성하기

LiteDBStatement의 close 메소드를 호출하면 진행중이던 Query 수행을 중단합니다.

/* Stop 버튼 onclick 이벤트 함수 */
this.btn_stop_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBStatement00.close();        
};

9

모바일 장치에서 확인하기

화면이 로딩되면 데이터베이스가 자동으로 연결됩니다. 정상적으로 연결이 수행되어 Grid에 TB_POS 테이블의 데이터가 출력되는지 확인합니다.

쿼리문을 선택하고 Query 버튼을 터치합니다. 쿼리가 정상적으로 수행되면 Grid에 수행 결과가 반영되는지 확인합니다.

쿼리 수행중 Stop 버튼을 터치하여 수행중이던 쿼리가 중단되는지 확인합니다.

11.5트랜잭션 설정하기

데이터베이스에서는 데이터의 무결성을 보장하는 것이 무엇보다 중요합니다. 데이터베이스의 상태를 변경하는 도중 발생할 수 있는 치명적 오류로부터 데이터를 보호하기 위한 메커니즘이 트랜잭션입니다.

SQLite는 기본적으로 트랜잭션을 지원합니다. AUTOCOMMIT 모드를 지원하므로 사용자가 별도로 트랜잭션을 설정하지 않더라도 내부적으로 SQL 연산이 하나의 트랜잭션 내에서 수행되도록 처리합니다. 별도의 설정이 필요없기에 사용이 편리하지만 모든 SQL 연산마다 트랜잭션 설정/해제가 반복되므로 많은 양의 데이터를 입력하거나 여러 개의 SQL 문으로 구성된 복합 연산이 필요할 때는 비효율적일 수 있습니다. 이런 경우에는 사용자가 직접 트랜잭션을 설정하고 커밋/롤백을 수행할 필요가 있습니다.

본 절에서는 사용자가 명시적으로 트랜잭션을 설정하고 이를 데이터베이스에 반영하는 Commit과 취소하는 Rollback 기능을 사용하는 방법에 관해 설명합니다.

11.5.1예제

다음은 데이터베이스에 연결하고 트랜잭션을 설정한 후 SQL 연산을 수행하여 그 결과를 Grid로 출력하는 예제입니다.

화면이 로딩되면 자동으로 데이터베이스 연결을 수행하며 TB_POS 테이블을 조회하여 데이터를 Grid로 출력합니다. 데이터베이스 연결이 완료되면 쿼리문을 선택하고 Query 버튼을 터치합니다. 쿼리가 수행된 결과는 즉시 Grid로 반영됩니다.

화면이 로딩되면 자동으로 데이터베이스 연결을 수행하며 TB_POS 테이블을 조회하여 데이터를 Grid로 출력합니다. 데이터베이스 연결이 완료되면 Begin 버튼을 터치하여 트랜잭션을 설정할 수 있습니다. 트랜잭션이 설정된 후 적절한 쿼리문을 선택하고 Query 버튼을 터치하여 데이터를 입력, 삭제 혹은 변경하는 SQL 연산을 수행합니다. 수행된 결과는 즉시 Grid로 반영되어 확인할 수 있습니다.

쿼리 수행이 끝나고 변경된 내용을 데이터베이스에 반영하려면 Commit 버튼을 터치하고 취소하려면 Rollback 버튼을 터치합니다. 트랜잭션 도중에 애플리케이션을 종료하면 그동안의 SQL 연산은 자동으로 Rollback 처리됩니다.

그림 11-5example_litedb_03

11.5.2예제에서 사용한 핵심 기능

LiteDBConnection > begin 메소드

데이터베이스에 트랜잭션을 설정하는 메소드입니다.

LiteDBConnection > commit 메소드

트랜잭션이 설정된 데이터베이스에 변경된 내용을 반영하는 메소드입니다. commit을 수행하면 트랜잭션 설정이 해제됩니다.

LiteDBConnection > rollback 메소드

변경된 내용을 트랜잭션이 설정되기 전 상태로 되돌리는(취소) 메소드입니다. rollback을 수행하면 트랜잭션 설정이 해제됩니다.

11.5.3예제 구현 방법

1

화면 구성하기

LiteDBConnection, LiteDBStatement 오브젝트를 추가합니다. 추가된 오브젝트는 Invisible Object 창에서 확인할 수 있습니다.

데이터베이스 파일 경로를 입력 혹은 표시할 Edit 컴포넌트와 사용자로부터 수행을 명령을 받기 위한 Button 컴포넌트를 예제의 그림과 같이 적절히 배치합니다. 추가로 정상적으로 데이터베이스가 오픈됐는지 확인하기 위한 Grid 컴포넌트와 Dataset 오브젝트도 추가합니다.

화면 구성을 위해 사용한 컴포넌트 및 오브젝트는 다음과 같습니다.

컴포넌트/오브젝트

ID

LiteDBConnection

LiteDBConnection00

LiteDBStatement

LiteDBStatement00

Static

stt_transaction

Dataset

ds_sqlite

Grid

Grid00

GroupBox

GroupBox00

GroupBox01

GroupBox02

Edit

edt_dbfile

ExtCombo

ExtCombo00

Button

btn_query

btn_begin

btn_commit

btn_rollback

2

Form 이벤트 함수 작성하기

폼 로딩 후 데이터베이스가 연결되어 있는지 확인할 onload 이벤트 함수를 작성합니다.

/* Form의 onload 이벤트 함수 */
this.sample_litedb_03_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo)
{
    this.LiteDBConnection00.isConnected();
};

3

Database 그룹의 Edit 컴포넌트 설정하기

추가한 Edit 컴포넌트의 value 속성을 '%USERAPP%File/nexacro_edu_db.sqlite'로 설정합니다. 이 파일은 SQLite 파일로 프로젝트와 함께 샘플로 제공된 파일로 넥사크로 스튜디오의 Project Explorer에서 File 디렉터리에서 확인할 수 있습니다.

4

Query 그룹의 ExtCombo 설정하기

ExtCombo 컴포넌트의 innerdataset 속성에서 편집기를 오픈하여 innerdataset을 설정합니다. 예제에서 사용할 SQL 쿼리문을 다음과 같이 입력합니다.

그림 11-6example_litedb_02_01

ExtCombo 컴포넌트의 속성을 다음과 같이 설정합니다. innerdataset을 바인딩 해주고 ExtCombo 클릭시 오픈될 팝업 윈도우 폼을 popupurl 속성에 설정합니다.

속성

popupurl

Base::pExtCombo.xfdl

innerdataset

innerdataset

codecolumn

codecolumn

datacolumn

datacolumn

5

Query 그룹의 Query 버튼 이벤트 함수 작성하기

우선 예제와 같이 두 개의 Query 버튼에 대해 각각 아래와 같이 onclick 이벤트 함수를 작성합니다.

/* Query 버튼 onclick 이벤트 함수 */
this.btn_query_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{    
    this.execute_query(this.ExtCombo00.text);
};

위의 onclick 이벤트 함수에서 사용된 execute_query는 입력된 쿼리문을 분석하여 어떤 메소드를 호출할지 결정해주는 함수입니다. 이는 쿼리문에 따라 쿼리를 수행하는 메소드가 다르기 때문으로 select 문은 executeQuery 메소드를 사용해야 하고 insert, update, delete 문은 executeUpdate 메소드를 사용해야 하기 때문입니다.

/* execute_query 함수 */
this.execute_query = function(strQuery)
{
    this.LiteDBStatement00.set_query(strQuery);
    var arrString = this.LiteDBStatement00.query.split(" ");    
    
    switch(arrString[0])
    {
        case "select":
            this.LiteDBStatement00.executeQuery();
            break;
            
        case "insert":
        case "update":
        case "delete":
            this.LiteDBStatement00.executeUpdate();
            break;
            
        default:
            alert(arrString[0] + " is illegal query statement.");
    }
}

6

Transaction 그룹의 Begin, Commit, Rollback 버튼 이벤트 함수 작성하기

/* Begin 버튼의 onclick 이벤트 함수 */
this.btn_begin_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBConnection00.begin();    
};
/* Commit 버튼의 onclick 이벤트 함수 */
this.btn_commit_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBConnection00.commit();    
};
/* Rollback 버튼의 onclick 이벤트 함수 */
this.btn_rollback_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    this.LiteDBConnection00.rollback();    
};

7

LiteDBConnection 이벤트 함수 작성하기

LiteDBConnection 오브젝트에서 발생한 이벤트를 처리하기 위한 함수를 작성합니다. LiteDBConnection의 메소드 호출을 성공하면 onsuccess 이벤트가 발생하는데 e.reason 값을 통해 어떤 메소드가 호출됐는지 알 수 있습니다.

/* LiteDBConnection 오브젝트 onsuccess 이벤트 함수 */
this.LiteDBConnection00_onsuccess = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBEventInfo)
{
    switch(e.reason)
    {
        case 1:    // LiteDBConnection begin()
            this.btn_begin.set_enable(false);
            this.btn_commit.set_enable(true);
            this.btn_rollback.set_enable(true);
            this.stt_transaction.set_visible(true);
            alert("Transaction setup succeeded.");            
            break;
            
        case 2:    // LiteDBConnection close()
            this.Grid00.set_visible(false);
            this.btn_query.set_enable(false);
            this.btn_begin.set_enable(false);
            this.btn_commit.set_enable(false);
            this.btn_rollback.set_enable(false);
            this.stt_transaction.set_visible(false);
            break;
            
        case 3: // LiteDBConnection commit()
            this.btn_commit.set_enable(false);
            this.btn_rollback.set_enable(false);        
            this.stt_transaction.set_visible(false);
            this.btn_begin.set_enable(true);
            alert("Commit succeeded.");            
            this.LiteDBStatement00.executeQuery("select * from tb_pos");
            break;
            
        case 4: // LiteDBConnection isConnected()
            alert("Already connected to DB.");
            break;
            
        case 5: // LiteDBConnection open()
            this.Grid00.set_visible(true);
            this.btn_query.set_enable(true);
            this.btn_begin.set_enable(true);

            this.LiteDBStatement00.set_ldbconnection(this.LiteDBConnection00);
            this.LiteDBStatement00.executeQuery("select * from tb_pos");
            break;
            
        case 6:    // LiteDBConnection rollback()
            this.btn_commit.set_enable(false);
            this.btn_rollback.set_enable(false);        
            this.stt_transaction.set_visible(false);
            this.btn_begin.set_enable(true);
            alert("Rollback succeeded.");        
            this.LiteDBStatement00.executeQuery("select * from tb_pos");
            break;
            
        default:
            break;
    }
};

LiteDBConnection의 메소드 호출에 실패하면 onerror 이벤트가 발생하는데 e.statuscode 값을 통해 어떤 메소드 수행시 에러가 발생했는지 확인할 수 있습니다.

/* LiteDBConnection 오브젝트 onerror 이벤트 함수 */
this.LiteDBConnection00_onerror = function(obj:nexacro.LiteDBConnection,e:nexacro.LiteDBErrorEventInfo)
{    
    switch(e.statuscode.toString())
    {
        case "1201":    //DB response timeout error
            alert("DB response timeout.");
            break;
            
        case "1202":    //LiteDBConnection begin() error
            alert("Transaction setup failed.");
            break;
            
        case "1203":    //LiteDBConnection close() error
            alert("DB close failed.");
            break;
            
        case "1204":    //LiteDBConnection commit() error
            alert("Commit failed.");
            break;
            
        case "1205":    //LiteDBConnection isConnected() error
            this.LiteDBConnection00.set_datasource(this.edt_dbfile.value);
            this.LiteDBConnection00.open();                
            break;
            
        case "1206":    //LiteDBConnection open() error
            alert("DB open failed.");
            break;
            
        case "1207":    //LiteDBConnection rollback() error
            alert("Rollback failed.");
            break;
            
        case "00001":    //Parameter setting error
            alert("Parameter setting error.");
            break;
            
        default:        //Unknown error        
            var strResult = "[LiteDBConnection00_onerror]";    
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;            
            alert(strResult);                
    }
    
};

8

LiteDBStatement 이벤트 함수 작성하기

LiteDBStatement 오브젝트에서 발생한 이벤트를 처리하기 위한 함수를 작성합니다. LiteDBStatement의 메소드 호출을 성공하면 onsuccess 이벤트가 발생하는데 e.reason 값을 통해 어떤 메소드가 호출됐는지 알 수 있습니다.

/* LiteDBStatement 오브젝트 onsuccess 이벤트 함수 */
this.LiteDBStatement00_onsuccess = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBEventInfo)
{    
    switch(e.reason)
    {
        case 7:    // LiteDBStatement executeQuery()
            this.ds_sqlite.copyData(e.returnvalue);
            this.ds_sqlite.set_keystring("S:+POS_CD+POS_NAME");
            this.Grid00.createFormat();        
            break;
            
        case 8:    // LiteDBStatement executeUpdate()
            this.LiteDBStatement00.executeQuery("select * from tb_pos");
            break;
            
        case 9:    // LiteDBStatement close()
            alert("Query execution stopped.");
            break;
            
        default:
            break;
    }    
};

LiteDBStatement의 메소드 호출에 실패하면 onerror 이벤트가 발생하는데 e.statuscode 값을 통해 어떤 메소드 수행시 에러가 발생했는지 확인할 수 있습니다.

/* LiteDBStatement 오브젝트 onerror 이벤트 함수 */
this.LiteDBStatement00_onerror = function(obj:nexacro.LiteDBStatement,e:nexacro.LiteDBErrorEventInfo)
{
    switch(e.statuscode.toString())
    {
        case "1210":    //LiteDBStatement executeQuery() error
            alert("LiteDBStatement executeQuery() error.");
            break;
            
        case "1211":    //LiteDBStatement executeUpdate() error
            alert("LiteDBStatement executeUpdate() error.");
            break;
            
        case "00001":    //Parameter setting error
            alert("LiteDBStatement parameter setting error.");
            break;
            
        default:        //Unknown error        
            var strResult = "[LiteDBStatement00_onerror]";    
            strResult += "\n["+ e.errortype +" "+ e.statuscode +"] "+ e.errormsg;
            strResult += "\ne.ldberrorcode: "+ e.ldberrorcode;
            strResult += "\ne.ldberrormsg: "+ e.ldberrormsg;            
            alert(strResult);
    }
};

9

모바일 장치에서 확인하기

화면이 로딩되면 데이터베이스가 자동으로 연결됩니다. 정상적으로 연결이 수행되어 Grid에 TB_POS 테이블의 데이터가 출력되는지 확인합니다.

Transaction 그룹의 Begin 버튼을 터치하여 오픈된 데이터베이스에 트랜잭션을 설정합니다. 트랜잭션 설정이 성공하면 "The transaction has been set"이라는 문구가 출력됩니다.

Query 그룹에서 쿼리문을 선택한 후 Query 버튼을 터치하여 쿼리를 수행합니다. 쿼리가 정상적으로 수행되면 그 즉시 Grid에 수행 결과가 반영됩니다.

쿼리 수행을 모두 완료한 후 변경된 내용을 데이터베이스에 반영하려면 Commit 버튼을 터치하고, 취소하려면 Rollback 버튼을 터치합니다. Commit이나 Rollback 버튼을 터치하면 트랜잭션 설정이 해제됩니다.