() 붕붕영화 예매시스템을 구성하는 클래스중 여러분이 구현하지 않아도 될 기본클래스가

있습니다. 이는 여러분이 붕붕영화 예매시스템 개발에 참여하기 전에 ()붕붕영화 시스템

개발부에서 만들어 놓은 객체들입니다.(SCJD 실제 시험에서도 이와 유사합니다.)

이 객체들은 대부분 데이터베이스 관련 객체들인데, 여기서는 이 객체들의 역할이 무엇이고

어떤 것들인지 살펴보도록 하겠습니다.

 

데이터베이스 레코드 칼럼(Column)정보

Field 클래스

데이터베이스에 저장되어 있는 레코드들은 어떤 칼럼을 갖고 있을텐데, Field클래스는 그

칼럼에 대한 설명을 하는 역할을 합니다.

데이터베이스는 레코드들의 모임이며,레코드는 몇 개의 칼럼으로 구성되어 있는데,Field

클래스는 레코드를 구성하는 칼럼 정보를 구현한 클래스입니다.

기본적인 생각은 칼럼은 이름이 있으며,칼럼 데이터는 일정한 길이가 있습니다.

관계형 데이터베이스의 테이블 구조를 생각해보면 테이블은 칼럼이름이 있고, 칼럼의

데이타형, 그리고 칼럼길이가 있는데 Field 클래스는 이중 칼럼이름과 칼럼 길이를

형상화 했습니다.

 

package movie;

 

/**

* 이 클래스는 레코드를 구성하는 칼럼에 대한 정보입니다.

* 레코드를 구성하는 칼럼들은 모두 이름이 있으며, 길이가 있습니다.

* Field 객체는 칼럼의 이름과,길이정보를 가지고 있습니다.

*

* @author djkim

* @version 1.0

* @since 2003.05

*/

public class Field implements java.io.Serializable {

            

   /**

    * column의 이름입니다.

    */

             private String name;

 

   /**

    * column의 길이입니다.

    */   

             private int length;

 

 

   /**

    * 레코드의 column에 대한 정보인 column이름,column length 생성합니다.

    * @param String name column 이름

    * @param int length column 길이

    *

    */   

             public Field(String name, int length) {

                           this.name = name;

                           this.length = length;

             }

            

 

   /**

    * column의 이름을 구합니다.

    * @return String column 이름

    */                 

             public String getName() {

                           return name;

             }

   /**

    * column의 길이를 구합니다.

    * @return String column 이름

    */                              

             public int getLength() {

                           return length;

             }

}

예제 18 - 3 Field.java

 

예제 18 - 3은 레코드의 한 칼럼 정보를 자바로 구현한 내용입니다.

1개 레코드를 이루는 칼럼이 N개 라면 칼럼에 대한 설명도 N개이므로 Field객체도

N개가 필요할 것입니다.

데이터베이스에 레코드가 N개의 칼럼으로 이루어져 있으면 데이터베이스의 레코드를

설명하는데 N개의 Field객체가 필요합니다. Field객체는 네트워크를 통해서 데이터베이스

서버와 GUI 클라이언트간에 이동을 해야하기 때문에 java.io.Serializable을 구현했습니다.

 

데이터베이스 레코드

Record 클래스

Record 클래스는 데이터베이스에 저장되어 있는 레코드를 구현한 클래스입니다.

 

()붕붕영화 시스템 개발부에서 만든 데이터베이스는 강력한 관계형 데이타베이스가

아니어서 데이타베이스에 레코드를 추가 또는 수정하는 경우와 레코드를 삭제하는 경우

레코드 처리 메카니즘에 차이가 있습니다.

데이터베이스에 레코드를 추가할 때는 물리적인 데이터를 가지고 있는 레코드가 물리적인

데이터베이스 파일에 추가 됩니다.

좀 더 낮은 레벨로 살펴보면 바이너리 데이타가 데이터베이스 파일에 추가되고

데이터베이스 파일의 물리적 크기가 커집니다. 수정의 경우는 이미 데이이타베이스에

포함되어 있는 레코드의 내용이 변경되는 것이므로 물리적으로 레코드가 위치한 곳의

바이너리 데이터가 변경 됩니다. 데이타베이스 파일의 전체 크기는 변경이 없습니다.

 

붕붕영화 예매시스템 데이터베이스에서 레코드의 삭제는 레코드 추가와 확연히 구분되는데,

데이터베이스에서 레코드를 삭제했다고 해서 삭제된 레코드가 물리적으로 데이터베이스에서

사라지는 것이 아닙니다. 붕붕영화 예매시스템 데이터베이스에서 레코드를 삭제한다는 것은

물리적으로 레코드를 지워 없애는 것이 아니라 존재하는 레코드에 삭제 표시만 합니다.

그러니까 데이터베이스에서 레코드가 삭제 된다고 하더라도 데이터베이스의 물리적인크기는

줄어들지 않습니다. 데이터베이스에 존재하는 모든 물리적인 레코드들은 삭제 여부 Flag

가지고 있는데, Flag의 값에 따라 존재하는 레코드와 삭제된 레코드로 구별됩니다.

 

레코드가 가지는 의미있는 변수는 String 배열인 values입니다.

데이터베이스에 있는 레코드는 N개의 칼럼으로 구성되어 있는데, String[] values

칼럼의 값을 보관하는 멤버변수입니다.

붕붕영화 데이타베이스 레코드의 모든 칼럼의 데이타형은 String 형입니다.

그리고 레코드의 첫번째 칼럼은 해당 레코드의 키입니다.

 

간명하게 말하면 레코드는 String형태의 N개의 칼럼 값을 가지고 있으며, 첫번째 칼럼이

데이타베이스의 레코드를 구분하는 Primary Key값 입니다.

 

레코드 객체가 가지는 멤버변수중에 int recordLength가 있는데, 이 값은 레코드를

이루는 N개의 칼럼들의 길이를 모두 더한 값으로,물리적인 레코드의 길이라고 할 수

있습니다.

 

물리적인 데이터베이스 파일에 존재하는 레코드의 물리적인 길이는 recordLength보다

한바이트 더 큰데, 그 것은 레코드가 존재하는 레코드인지,삭제된 레코드인지 여부를

나타내는 Flag 정보 때문입니다.  실제 물리적인 데이터베이스 파일에 존재하는 레코드의

길이는 recordLength값에 Flag길이 1을 더한 길이입니다.

 

Record 객체에는 Field[] 변수가 있는데,이 변수는 레코드객체가 가지는 N개의 칼럼정보를

가지고 있습니다.  Field 객체는 칼럼이름과 칼럼길이를 나타냅니다.

레코드의 칼럼이 N개이면 Field 객체도 N개 있을 것입니다.

 

마지막으로 Record객체가 가지는 정보는 recno라는 int형 변수가 있는데, 이 변수의 의미는

데이터베이스 파일에서 현재 Record객체가 몇번째 레코드인지, 그 순서값입니다.

 

붕붕영화 예매시스템에 사용되는 데이터베이스 파일은 레코드를 삭제하더라도 물리적으로는

크기가 줄어 들지 않습니다. recno 변수의 의미는 레코드에게 부여된 레코드 번호라는 의미

보다는 데이터베이스에서 현재 레코드의 위치가 처음부터 몇번째 레코드인것인가하는 의미

일 것입니다. 물론 삭제되지 않은 레코드, 삭제된 레코드를 모두 포함해서 말입니다.

 

package movie;

 

/**

* 데이타베이스에 저장되는 레코드를 나타내는 클래스입니다.

* 레코드는 레코드의 값을 String[] 형태로 가지고 있습니다.

* 데이타베이스에 존재하는 레코드는 삭제된 레코드와 삭제되지 않은 레코드로 구분되는데

* 삭제된 레코드는 데이타베이스에서 물리적으로 없어지는 것은 아닙니다.

* 레코드는 Flag값을 기준으로 삭제된 레코드, 삭제되지 않은 레코드로 구분합니다.

*

* @author djkim

* @version 1.0

* @since 2003.05

*/

public class Record implements java.io.Serializable {

 

   /**

    * 레코드의 값

             */

             private String[] values;

   /**

             * 존재하는 레코드인지, 삭제표시된 레코드인지 나태내는 flag

             */

             private byte flag;

   /**

    * 레코드의 길이

    */

             private int recordLength = 0;

   /**

             * 레코드의 column정보를 나타냅니다.

             */

             private Field[] fields;

   /**

             * 레코드의 번호

             */

             private int recno;

 

   /**

    * String[] 데이타와  Field[]에 있는 길이정보를 이용해서

    * 레코드의 column값을 구성합니다.

    * @param byte flag 존재하는 레코드인지 , 삭제된 레코드인지 표시합니다.

    * @param String[] values String배열 형태의 레코드 데이타입니다.

    * @param Field[] field 레코드를 구성하는 길이정보를 갖고 있습니다.

    * @param int recno 레코드번호입니다.

    */

             public Record(byte flag, String[] values,Field[] fields,int recno) {

                           this.flag = flag;                                 // 레코드의 삭제여부 flag

                           this.values = values;                        // 레코드의 column

                           this.fields = fields;              // 레코드의 column의 이름 및 길이정보

                          

                           for(int i = 0; i < fields.length; i++) {

                                        int len = fields[i].getLength();           

                                        this.recordLength += len;     // 레코드의 길이, 레코드의 column 길이의 합

                           }

                           this.recno = recno;                                        // 레코드 번호

             }

 

    /**

    * String[] 데이타와  Field[]에 있는 길이정보를 이용해서

    * 레코드의 column값을 구성합니다.

    * @param byte flag 존재하는 레코드인지 , 삭제된 레코드인지 표시합니다.

    * @param String[] values String배열 형태의 레코드 데이타입니다.

    * @param Field[] field 레코드를 구성하는 길이정보를 갖고 있습니다.

    */

             public Record(byte flag, String[] values,Field[] fields) {

                           this(flag,values,fields,-1);   

             }

            

   /**

    * byte[] 데이타와  Field[]에 있는 길이정보를 이용해서

    * 레코드의 column값을 구성합니다.

    * @param byte flag 존재하는 레코드인지 , 삭제된 레코드인지 표시합니다.

    * @param byte[] data byte배열 형태의 레코드 데이타입니다.

    * @param Field[] field 레코드를 구성하는 길이정보를 갖고 있습니다.

    * @param int recno 레코드번호입니다.

    */

             public Record(byte flag, byte[] data, Field[] fields, int recno) {

                           this.flag = flag;                   // 레코드의 삭제여부 flag

                           // 레코드의 column값을 보관하는 values[] 생성

                           this.values = new String[fields.length];

                           // 레코드의 column이름 및 길이를 보관하는 fields생성

                           this.fields = fields;                           

                          

                           int offset = 0;

                           for(int i = 0; i < fields.length; i++) {

                                        int len = fields[i].getLength();

            // 레코드의 i번째 column값을 values[]에 보관                               

                                        this.values[i] = new String(data,offset,len);

                                        offset += len;

                           }

                           // 레코드의 길이, 레코드에 포함된 column의 총길이와 같음

                           this.recordLength = offset;                

        this.recno = recno;               // 레코드 번호                                           

             }

 

   /**

    * byte[] 데이타와  Field[]에 있는 길이정보를 이용해서

    * 레코드의 column값을 구성합니다.

    * @param byte flag 존재하는 레코드인지 , 삭제된 레코드인지 표시합니다.

    * @param byte[] data byte배열 형태의 레코드 데이타입니다.

    * @param Field[] field 레코드를 구성하는 길이정보를 갖고 있습니다.

    */

             public Record(byte flag, byte[] data, Field[] fields) {    

                           this(flag,data,fields,-1);

             }

 

   /**

    * 레코드가 존재하는지 , 삭제되었는지 나타내는 flag을 구합니다.

    * @return byte

    */

             public byte getFlag() {

                           return flag;

             }

   /**

    * 레코드가 존재하는지 , 삭제되었는지 나타내는 flag를 지정합니다.

    * @param byte flag 존재하는 레코드인지 , 삭제된 레코드인지 표시합니다.

    */   

             public void setFlag(byte flag) {

                           this.flag = flag;

             }

 

   /**

    * 레코드번호를 돌려줍니다.

    * @return int 레코드 번호

    */   

             public int getRecno() {

                           return recno;

             }

 

   /**

    * 레코드의 column정보를 알려줍니다.

    * @return Field[] 레코드의 column정보

    */                 

             public Field[] getFields() {

                           return fields;

             }

 

   /**

    * 레코드가 가지는 값을 알려줍니다.

    * @return String[] 레코드가 가지는 칼럼값들

    */                 

    public String[] getValues() {

                           return values;

             }

            

   /**

    * 레코드가 가지는 값을 지정합니다.

    * @param String[] values 레코드가 가지는 칼럼값들

    */                 

             public void setValues(String[] values) {

                           for(int i = 0; i < values.length; i++)

                                        this.values[i] = values[i];  

             }

            

   /**

    * 레코드가 가지는 값을 byte[]로 바꾸어 돌려줍니다.

    * @return byte[] 레코드가 가지는 칼럼값을 byte[]로 바꾸어 돌려줍니다.

    */                 

             public byte[] getBytes() {

                           // 레코드의 길이 만큼 byte[]를 만듭니다.

                           byte[] buf = new byte[recordLength];             

                           int offset = 0;

                          

                           // space byte배열 buf를 초기화합니다.

                           for(int i = 0 ; i < recordLength; i++)    

                                        System.arraycopy(" ".getBytes(),0,buf,i,1);

 

                           for (int i = 0; i < values.length; i++) {

                                        int len = 0;

                                        // 레코드의 i번째 column의 값을 byte[]로 바꿈

                                        byte[] data = values[i].getBytes();   

                                        if (data.length > fields[i].getLength()) {

                                                     len = fields[i].getLength();

                                                     // 레코드의 i번째 column buf에 추가       

                                                     System.arraycopy(data,0,buf,offset,len);                       

                                        }

                                        else {

                                                     len = data.length;

                                                     // 레코드의 i번째 column buf에 추가       

                                                     System.arraycopy(data,0,buf,offset,len);

                                        }

                                        offset += fields[i].getLength();

                           }

                           return buf;

             }

}

예제 18 - 4 Record.java

 

예제 18 - 4는 붕붕영화 예매시스템 데이타베이스에 존재하는 레코드를 자바로 구현한

내용입니다.

붕붕영화 예매시스템에 존재하는 레코드는 모두 N개의 칼럼으로 이루어져 있고,

N개의 칼럼은 모두 String 형이며, 첫번째 칼럼이 Primary Key 값을 갖고 있으며,

Flag 변수를 갖고 있어서 Flag 값에 따라 존재하는 레코드(의미있는 레코드),

삭제된 레코드로 분리됩니다.

붕붕영화 데이타베이스는 레코드가 삭제된다고 하더라도 물리적으로 레코드가 사라지는

것은 아닙니다.

 

데이터베이스 예외

DatabaseException 클래스

DatabaseException클래스는 붕붕영화 예매시스템에서 데이타베이스를 사용할 때 발생하는

예외를 형상화했습니다.

붕붕영화 예매시스템 자체가 간단한 시스템이어서 DatabaseException 역시 간명하게 구현

했습니다.

 

package movie;

 

/**

* 붕붕영화 데이타베이스를 생성할때, 혹은 데이타베이스로부터 레코드를

* 읽고,쓸때 발생한 예외를 정의합니다.

*

* @author djkim

* @version 1.0

* @since 2003.05

*/

public class DatabaseException extends Exception {

             /**

             * 붕붕영화 데이타베이스 예외를 생성합니다.

             */

    public DatabaseException() {

           super();

    }

             /**

             * 붕붕영화 데이타베이스 예외를 생성합니다.

             *

             * @param msg 데이타베이스 예외를 설명합니다.

             */

    public DatabaseException(String msg) {

        super(msg);

    }

             /**

             * 붕붕영화 데이타베이스 예외를 생성합니다.

             *

             * @param e 데이타베이스 예외를 초래한 예외입니다.

             */   

    public DatabaseException(Exception e) {

           super(e.getMessage());

    }

}

예제 18 - 5 DatabaseException.java

 

DatabaseException 클래스는 3개의 생성자를 오버로딩하여 사용하기 편리하도록 했습니다.

 

붕붕영화 데이타베이스

Movie 클래스

Movie 클래스는 붕붕영화 예매시스템에서 사용하는 데이타베이스입니다.

여러분이 붕붕영화 예매시스템 프로젝트에 참가하기 이전에 ()붕붕영화 시스템개발부에서

만든 로컬에서 읽고,쓰는 Thread Safe하지 않고 검색기능도 없는 데이터베이스입니다.

그야말로 파일을 데이타소스로 하는 가장 기본적인 데이터베이스 기능을 수행합니다.

 

Movie 클래스가 가지는 RandomAccessFile 데이터형 멤버변수 db Movie 클래스가

다루는 물리적인 데이터베이스 파일을 가리킵니다.

Movie 클래스는 물리적인 데이터 저장공간으로 파일를 사용하는데,데이타베이스의 특성상

특정 레코드가 위치하고 있는 곳으로 쉽게 이동해서 읽고,쓰기를 해야하므로

RandomAccessFile 객체를 선택했습니다.

특정위치의 레코드를 찾는 것은 특정위치의 레코드가 있는 곳으로 파일 포인터를 옮기면

되고, 이런 행동은 RandomAcessFile 객체의 public void seek(long) 메소드를 이용하면

간단합니다. Movie 클래스는 두개의 public static 변수가 있는데 LIVE DEAD입니다.

각각 byte형 변수이며, 의미는 데이터베이스에 존재하는 레코드가 삭제표시된 레코드인지,

존재하는 레코드인지를 구별하는데 사용됩니다. 이 변수들은 어느 클래스에서도 그냥 읽을

서 사용할 수 있도록 public static 으로 지정했습니다. 그리고 값은 변해서는 안되므로 final

키워드를 지정했습니다.

 

Movie 클래스에는 데이터베이스를 다루기 위한 메타정보를 가지고 있는데, 데이터베이스에

기록된 데이타 레코드를 다루는데 사용하는 것이 아니라 데이터베이스 자체에 대한 정보를

다룰때 사용하는 멤버변수 headerLength,recordCount,fieldCount 입니다.

 

recordCount는 데이터베이스에 레코드가 추가될 때 마다 1씩 증가합니다.

현재 데이터베이스에 레코드가 97개 있다면 recordCount 97입니다.

recordCount는 레코드가 추가될 때 만다 1씩 증가하지만,레코드가 삭제될 때는 감소하지

습니다. 그러니까 recordCount의 실제적인 의미는 데이터베이스에 존재하는 삭제되지 않은

레코드와 삭제된(삭제표시된) 레코드의 갯수의 합이라고 보면 옳을 것입니다.

 

fieldCount는 레코드를 이루는 칼럼 개수와 같습니다. 그러니까 레코드가 N개 칼럼으로

이루어져 있다면 N 값을 가집니다. 좀더 정확한 의미는 레코드를 구성하는 칼럼 정보를

갖고 있는 Field객체의 개수이지만,Field의 개수가 바로 레코드를 이루는 칼럼 개수와

동일하므로 같은 의미입니다.

 

headerLength는 좀 독특한 정보입니다. 데이터베이스에는 크게 두가지의 정보가 함께

들어 있는데, 한가지는 데이터베이스 자체에 대한 정보이고 나머지는 데이터베이스에

존재하는 데이터 레코드에 대한 정보입니다.

headerLength는 데이터베이스 자체에 대한 정보인 데이타베이스 헤더 정보의 길이를

의미합니다. 즉 붕붕영화 데이타베이스는 headerLength 길이 만큼의 메타 정보를

갖고 있습니다. 물론 recordLength 만큼의 데이타 레코드를 갖고 있구요.

 

Movie 클래스는 데이터베이스를 처음 초기화할 때,존재하는 데이타 파일로부터 데이타

레코드를 로드하여 데이타베이스를 초기화 할 수 있습니다.

 

 

package movie;

 

import java.io.*;

 

/**

 * Movie 클래스는 기본적인 데이타베이스 기능인

 * 레코드 추가,삭제,수정등의서비스를 제공합니다.

 *

 * @author djkim

 * @version 1.0

 * @since 2003.05

 */

public class Movie {

    /**

     * 레코드를 저장하는 데이타소스입니다.

     */

             private RandomAccessFile db;

 

    /**

     * 데이타베이스에 저장되어 있는 레코드가 삭제된 레코드인지,존재하는

     * 레코드인지를 표시하는 상수입니다.

     * 레코드의 첫번째 바이트가 0x01이면 존재하는 레코드입니다.

     */

             public static final byte LIVE = 0x01;

 

    /**

     * 데이타베이스에 저장되어 있는 레코드가 삭제된 레코드인지,존재하는

     * 레코드인지를 표시하는 상수입니다.

     * 레코드의 첫번째 바이트가 0x00이면

     * 삭제된 레코드입니다.

     */

             public static final byte DEAD = 0x00;

 

    /**

     * 데이타베이스에 대한 정보를 가지고 있는 헤더부분만의 길이입니다.

     */

             private long headerLength = 0;

            

    /**

     * 데이타베이스에 대한 존재하는 레코드의 갯수입니다.

     */  

             private int recordCount = 0;

 

    /**

     * 데이타베이스에 존재하는 Field의 갯수입니다.

     * 레코드를 이루는 칼럼의 갯수과 같습니다.

     */

             private int fieldCount = 0;

            

             /**

              * 레코드의 칼럼 정보를 입니다. 칼럼정보는 칼럼이름과 칼럼의 길이로 구성됩니다.

              */

             protected Field[] fields;

            

    /**

     * 레코드의 길이입니다.

     * 레코드의 길이는 레코드를 이루는 칼럼의 길이부분을 모두 합한 것입니다.

     */

             private int recordLength = 0;

 

    /**

     * 데이타베이스를 읽고,쓰는 도중에 물리적,논리적 오류시 사용하는

     * 메시지입니다.

     */

    protected static final String UNEXPECTED =

    "데이타베이스에 예상하지 못한 문제가 생겼습니다!!!";

 

    /**

     * 데이타베이스 파일 dbname을 엽니다.

     * 데이타베이스의 구성은 long형 데이타베이스 헤더정보길이,

     * int형 레코드의 갯수,ing Field의 갯수,Field 정보 칼럼이름,칼럼 길이

     * 그리고 실제 레코드들로 구성됩니다.

     *

     * @param dbname 데이타소스의 이름

     * @exception IOException 데이타베이스 파일이 존재하지 않을때*/

             public Movie(String dbname) throws IOException {

                           File f = new File(dbname);                             // 데이타베이스 파일 dbname

                           if (f.exists()) {                                                         // 데이타베이스 파일 dbname이 존재

                                        db = new RandomAccessFile(f,"rw");

                                        headerLength = db.readLong();         // 데이타베이스 헤더길이 정보

                                        recordCount = db.readInt();               // 데이타베이스 레코드의 갯수

                                        fieldCount = db.readInt();                               // 데이타베이스 레코드의 칼럼 갯수

                                        fields = new Field[fieldCount];         

                                       

                                        // 데이타베이스 레코드의 칼럼 정보를 구합니다.

                                        for (int i = 0; i < fieldCount; i++) {

                                                     String name = db.readUTF();                           // 칼럼의 이름

                                                     int len = db.readInt();                                     // 칼럼의 길이

                                                     fields[i] = new Field(name,len);

                                                     recordLength += len;

                                        }           

                           }

                           else {                               // 데이타베이스 파일 dbname이 존재하는 않는 경우

                                        throw new IOException("영화 데이타베이스 " + dbname + " 가 없습니다!!!");

                           }

             }

 

    /**

     * 데이타베이스 파일 dbname을 구성합니다.

     * 데이타베이스의 구성은 long형 데이타베이스 헤더정보길이,

     * int형 레코드의 갯수,ing Field의 갯수,Field 정보 즉 칼럼이름,칼럼길이

     * 그리고 실제 레코드들로 구성됩니다.

     *

     * @param dbname 데이타베이스 파일의 이름

     * @param fields 데이타베이스의 레코드 칼럼정보

     * @exception IOException 데이타베이스 파일이 이미 존재할경우

     */

             public Movie(String dbname,Field[] fields) throws IOException {

                           File f = new File(dbname);   // 데이타베이스 파일 dbname

                           this.fields = fields;

                           if (!f.exists()) {                                              // 데이타베이스 파일이 없습니다.

                                        db = new RandomAccessFile(f,"rw");

                                       

                                        fieldCount = fields.length;    // 레코드의 칼럼갯수

                                        /* 데이타베이스 헤더정보길이, 실제 레코드 갯수를 초기화 합니다.*/

                                        db.writeLong(0);              // 데이타베이스 헤더정보길이

                                        db.writeInt(0);                                  // 실제 레코드의 갯수

                                        db.writeInt(fieldCount);        // 레코드를 이루는 칼럼갯수

                                       

 

                                        // 데이타베이스 레코드의 칼럼정보를 지정합니다.                              

                                        for(int i = 0; i < fields.length; i++) {

                                                     String name = fields[i].getName();     // 칼럼이름

                                                     int len = fields[i].getLength();                                      // 칼럼길이

                                                     db.writeUTF(name);

                                                     db.writeInt(len);

                                                     recordLength += len;

                                        }

                                       

                                        headerLength = db.getFilePointer();   // 데이타베이스 헤더정보길이

                                        db.seek(0);                                                  // 데이타베이스 헤더정보의 위치를 처음으로 이동

                                        db.writeLong(headerLength);            // 데이타베이스 헤더정보기록

                                        db.seek(0);                                                               // 데이타베이스 읽기 포인터 0으로 초기화

                 }

                 else {                                                    // 데이타베이스 파일 dbname이 존재하는 경우

                                        String msg = "영화 데이타베이스 " + dbname + " 가 이미 존재합니다!!!";

                        throw new IOException(msg);

                 }

             }

            

 

    /**

     * 데이타베이스에 존재하는 레코드의 갯수를 구합니다.

     *

     * @return int 데이타베이스에 존재하는 레코드의 갯수

     */  

             public int getRecordCount() {

                           return recordCount;

             }

            

    /**

     * 데이타베이스 레코드의 칼럼 정보, 칼럼 정보는 칼럼 이름과 칼럼 길이입니다.

     *

     * @return Field[] 데이타베이스 레코드의 칼럼 정보

     */               

             public Field[] getFields() {

                           return fields;

             }

            

    /**

     * 데이타베이스에 존재하는 레코드의 길이, 모든 레코드는 동일한 길이를 가집니다.

     * 레코드의 길이는 레코드를 이루는 칼럼들의 길이의 합으로 이루어집니다.

     *

     * @return int 데이타베이스에 존재하는 레코드의 길이

     */               

             public int getRecordLength() {

                           return recordLength;

             }

 

    /**

     * recno 번째의 레코드가 위치하는 곳으로 파일 포인터를 옮깁니다.

     * 레코드의 순서는 1부터 시작합니다.

     *

     * @param recno 옮겨가야하는 레코드 번호

     * @exception IOException 데이타베이스로 읽기가 안될때 등

     */

    private synchronized void seek(int recno) throws IOException {

        db.seek(headerLength + ((recordLength + 1) * (recno - 1)));

    }

 

    /**

     * 데이타베이스로부터 recno번째 레코드를 구합니다. 레코드는 1번부터 시작합니다.

     *

     * @param recno recno번째 레코드

     * @return Record  recno번째 존재하는 레코드

     * @exception DatabaseException 범위를 벗어난 레코드를 지정하는 경우

     *                          recno번째 레코드가 데이타베이스에 없거나 삭제된 경우

     *                          데이타베이스로 읽기,쓰기가 안될때 등

     */

             public synchronized Record getRecord(int recno) throws DatabaseException {

           try {

                                        if (recno<1) {                                                                          // 잘못된 레코드 번호를 지정한 경우

                                      throw new DatabaseException("레코드 번호는 1이상이어야 합니다!!!");

                               }

                                        Record record = readRecord(recno);  // recno 번째에 위치한 레코드

                                        if (record.getFlag() == this.LIVE)                     // 레코드가 삭제 표시 되지 않은 경우

                                                     return record;

                                        else

                                                     throw new DatabaseException(recno + "번호 레코드는 없습니다!!!");

        } catch(IOException ex) {

            throw new DatabaseException(UNEXPECTED);        

        }

    }   

 

    /**

     * 데이타베이스에 한 레코드를 추가합니다.

     *

     * @param record 데이타베이스에 추가할 레코드

     * @exception DatabaseException 데이타베이스로 부터 읽기 쓰기가 안될때등

     */

    public synchronized void add(Record record) throws DatabaseException {

 

                           String[] values = record.getValues(); // 레코드의 칼럼 값

                           String key = values[0];                     // 레코드의 첫번째 칼럼이 레코드의 key값입니다.

        if (find(key) != null) {            // key값을 가지는 레코드가 이미 데이타베이스에 있을 경우

                                        String msg = key + "값을 가진 레코드가 이미 데이타베이스에 있습니다!!!";

            throw new DatabaseException(msg);

        }

        try {

        recordCount++;                                // 데이타베이스에 존재하는 레코드의 갯수를 증가

            seek(recordCount);                     // recordCount번째 레코드 위치로 이동

            writeRecord(record);                   // 레코드를 저장

            // 데이타베이스 헤더정보중 레코드 갯수 정보는 8번째 byte부터 4byte를 차지           

            db.seek(8);                   // 데이타베이스 헤더정보중  레코드 갯수정보 위치로 이동

            db.writeInt(recordCount);             // 데이타베이스 헤더정보에 레코드 갯수 1증가

        }

        catch (IOException e) {

            throw new DatabaseException(UNEXPECTED + e);

        }

    }    

 

   /**

    * 데이타베이스의  key에 해당되는 특정 레코드를 삭제표시합니다.

    *

    * @param key 특정 레코드의 키값

    * @exception DatabaseException 데이타베이스로 읽기쓰기가 안될때등

    */

    public synchronized void delete(String key) throws DatabaseException {

        try {

                                        Record record = find(key);                // key를 가지는 레코드

            int recno = record.getRecno();      // 찾은 레코드의 레코드번호 (레코드 위치)

            seek(recno);                                                                      // recno 번호 레코드위치로 이동

            record.setFlag(this.DEAD);                       // 레코드를 삭제 표시       

            writeRecord(record);                   // 삭제 표시된 레코드를 recno번호 위치에서 저장

        } catch (IOException e) {

            throw new DatabaseException(UNEXPECTED + e);

        }

    }       

 

    /**

     * 데이타베이스에 존재하는 Record객체를 수정합니다.

     *

     * @param record 수정하고 싶은 레코드

     * @exception DatabaseException 데이타베이스에 읽기, 쓰기가 안될때 등

     */

    public synchronized void modify(Record record) throws DatabaseException {

 

        try {

        String values[] = record.getValues(); // 레코드의 칼럼 값

        String key = values[0];                                                // 레코드의 첫번째 칼럼이 key

        Record rec = find(key);                                               // key값을 가진 레코드를 찾음

        int recno = rec.getRecno();                            //찾은 레코드 레코드번호(레코드위치)

            seek(recno);                                                                                   // recno번호 레코드로 이동

            writeRecord(record);      // recno번호 레코드위치에서 record overwrite

        } catch (IOException e) {

            throw new DatabaseException(UNEXPECTED + e);

        }

    }

 

    /**

     * 데이타베이스를 닫습니다.

     * 데이타베이스를 닫은 후에는 데이타베이스로 정보를 읽거나 쓸수 없습니다.

              *    

     */

    public synchronized void close() {

        try {

            db.close();                                 // 데이타베이스 파일을 닫습니다.

        } catch (IOException e) {}

        db = null;

    }

 

    /**

     * 데이타베이스의 자원을 해제합니다.

     */

    protected void finalize() {

        if (db != null) {

            close();

        }

    }

 

    /**

     * key값을 가진 레코드를 데이타베이스로 부터찾아냅니다.

     * 레코드를 데이타베이스로부터 찾지 못할 경우 null을 리턴합니다.

     * 레코드의 key값은 레코드가 가지는 여러개의 칼럼중에

     * 첫번째 칼럼이 레코드의 key입니다.

     *

     * @exception DatabaseException 데이타베이스로 읽기,쓰기가 안될때등

     * @return Record key값을 가진 레코드, key값을 가지는 레코드가 없을 경우 null

     * @param key 레코드의 key

     */

    public synchronized Record find(String key) throws DatabaseException {

        try {

            seek(1);          // 첫번째 레코드가 위치한 곳으로 이동

     

                        // 데이타베이스에 있는 첫번째 레코드부터 마지막 레코드까지 검사

            for (int r = 1; r <= recordCount; r++) {

                    

                Record record = readRecord(r);                                      // r번째 레코드를 찾음

               

                String values[] = record.getValues();   // 레코드의 칼럼값

                // 레코드의 첫번째 칼럼값이 key와 같고, 삭제 표시되지 않은 레코드

                                                     if (record.getFlag() == this.LIVE && values[0].equals(key)) {

                                                                  return record;

                                                     }

            }

                                        return null;            // key값을 가진 삭제되지 않은 레코드가 없는 경우

                                       

        }  catch (IOException e) {

            throw new DatabaseException(UNEXPECTED + e);

        }

    }  

 

    /**

     * 데이타베이스로 부터 지정한 번호(지정한 위치에)의 레코드를 구해냅니다.

              *    

     * @param recno 찾고자 하는 레코드번호(레코드 위치)

     * @return Record recno번호(recno에 위치한)를 가진 레코드

     * @exception IOException 데이타베이스로 읽기,쓰기가 안될때 등

     */

    

    private synchronized  Record readRecord(int recno) throws IOException {

                           seek(recno);                                   // recno번에 위치한 레코드로 이동

                          

        byte flag = (byte)db.read();// 레코드의 삭제여부 표시 flag

           

        byte[] data = new byte[recordLength];// 레코드의 길이(레코드 칼럼의 길이의 합)

        db.read(data,0,recordLength);            // 데이타베이스파일에서 레코드데이타 읽음

                   

        Record record = new Record(flag,data,this.fields,recno); // 레코드 객체 생성

        return record;

    }

   

    /**

     * 데이타베이스에 레코드를 추가합니다.

     *

     * @param record 데이타베이스에 추가할 레코드

     * @exception DatabaseException 데이타베이스로 읽기,쓰기가 안될때 등

     */

    private void writeRecord(Record record) throws IOException {

                           byte flag = record.getFlag();              // 레코드의 삭제여부 표시

                           byte[] data = record.getBytes();        // byte[]형태의 레코드 데이타

                           db.write(flag);                                                            // 데이타베이스에 삭제여부 등록

        db.write(data);                                                            // 데이타베이스에 데이타 등록

    }

}

예제 18 - 6 Movie.java

 

Movie 클래스는 붕붕영화 예매시스템에서 사용하는 데이타베이스를 구현한 클래스입니다.

Posted by
,