-
- 1. DBM
-
- 2. AnyDBM File
-
- 3. 서로 다른 DBM 포맷들 간의 복사
-
- 4. 복잡한 데이타
-
- 5. Multi-Level DBM (MLDBM)
-
- 6. 기타
-
- 7. comments
-
Perl에서 데이타베이스 사용하기
- 간단하게는 DBM(Database Manager) 모듈을 이용하여, tied hash를 통해 DB를 사용할 수 있음
- DBI(Database Interface)와 DBD(Database Driver) 모듈을 이용하여 MySQL등의 DB에 접근할 수 있음
DBM 데이타베이스는 간단한 키-밸류 형태의 DB를 구현
- index, binary tree, multiple table, transaction 등은 지원하지 않음
DBM 구현들. 각각의 DBM이 설치된 후에 Perl을 설치해야 해당 DBM을 쓸 수 있는 모듈이 생성된다.
- gdbm - GNU DBM. 빠르고 호환성 좋음. ndbm DB를 읽고 쓰는 것도 지원.
- ndbm - new DBM. UNIX시스템에 많이 쓰임
- odbm - old DBM. UNIX시스템에서 처음 사용되었던 구현. 웬만하면 쓰는 걸 피하자.
- sdbm - 펄 표준. gdbm 등보다 성능도 나쁘고 규모가 큰 DB에 적합하지 않으나 Perl이 설치되어 있다면 사용가능. 호환성 좋음
- bsd-db - Berkeley DB. 간단한 해시 포맷 뿐 아니라 바이너리 트리 포맷도 지원.
DBM을 사용한 간단한 데이타베이스
#!/usr/bin/perl
use warnings;
use strict;
use POSIX;
use SDBM_File;
my %dbm;
my $db_file = "simpledb.dbm";
tie %dbm, 'SDBM_File', $db_file, O_CREAT|O_RDWR, 0644;
if (tied %dbm) {
print "File $db_file now open.\n";
} else {
die "Sorry - unable to open $db_file\n";
}
$_ = "";
until (/^q/i) {
print "What would you like to do? ('o' for options): ";
chomp($_ = <STDIN>);
if ($_ eq "o") { dboptions() }
elsif ($_ eq "r") { readdb() }
elsif ($_ eq "l") { listdb() }
elsif ($_ eq "w") { writedb() }
elsif ($_ eq "d") { deletedb() }
elsif ($_ eq "x") { cleardb() }
else { print "Sorry, not a recognized option.\n"; }
}
untie %dbm;
sub dboptions {
print<<EOF;
Options available:
o - view options
r - read entry
l - list all entries
w - write entry
d - delete entry
x - delete all entries
EOF
}
sub readdb {
my $keyname = getkey();
if (exists $dbm{"$keyname"}) {
print "Element '$keyname' has value $dbm{$keyname}";
} else {
print "Sorry, this element does not exist.\n"
}
}
sub listdb {
foreach (sort keys(%dbm)) {
print "$_ => $dbm{$_}\n";
}
}
sub writedb {
my $keyname = getkey();
my $keyval = getval();
if (exists $dbm{$keyname}) {
print "Sorry, this element already exists.\n"
} else {
$dbm{$keyname}=$keyval;
}
}
sub deletedb {
my $keyname = getkey();
if (exists $dbm{$keyname}) {
print "This will delete the entry $keyname.\n";
delete $dbm{$keyname} if besure();
}
}
sub cleardb {
print "This will delete the entire contents of the current database.\n";
undef %dbm if besure();
}
sub getkey {
print "Enter key name of element: ";
chomp($_ = <STDIN>);
$_;
}
sub getval {
print "Enter value of element: ";
chomp($_ = <STDIN>);
$_;
}
sub besure {
print "Are you sure you want to do this?";
$_ = <STDIN>;
/^y/i;
}
2. AnyDBM File
AnyDBM File 모듈을 사용하면, 특정 DBM을 명시하지 않고, 시스템에 설치된 DBM을 사용할 수 있다.
use AnyDBM_File;
use POSIX;
my %dbm;
my $db_file="anydbmdemo.dbm";
tie (%dbm, 'AnyDBM_File', $db_file, O_CREAT|O_RDWR, 0644);
AnyDBM은 다음 순서로 DBM을 찾는다.
- NDBM_File, DB_File (버클리DB), GDBM_File, SDBM_File, ODBM_File
이 순서는 @ISA에 들어 있으므로, 만일 바꾸고 싶다면 다음과 같이 한다.
BEGIN {
@AnyDBM_File::ISA = qw(GDBM_File NDBM_File SDBM_File);
}
use AnyDBM_File;
- 이렇게 @ISA의 내용을 미리 바꾸는 것은 AnyDBM의 경우 @ISA가 미리 정의되었는지 확인하기 때문에 가능한 것이고, 아무 모듈에서나 되는 것은 아님에 유의
3. 서로 다른 DBM 포맷들 간의 복사
그냥 해쉬 변수들 간의 할당문으로 간편하게 된다. NDBM DB를 GDBM DB로 옮기는 경우의 예:
use POSIX;
use NDBM_File;
use GDBM_File;
my (%ndbm_db,%gdbm_db);
my $ndbm_file='/tmp/my_old_ndbm_database';
my $gdbm_file='/tmp/my_new_gdbm_database';
tie %ndbm_db, 'NDBM_File',$ndbm_file, O_RDONLY, 0;
tie %gdbm_db, 'GDBM_File',$gdbm_file, O_CREAT|O_WRONLY, 0644;
%gdbm_db=%ndbm_db;
untie %ndbm_db;
untie %gdbm_db;
4. 복잡한 데이타
리스트나 해쉬를 DBM DB에 저장하려면?
1) 직접 스칼라 형태로 변환하는 경우 - join, split 등을 사용
$dbm{'key'} = join ("_XYZ_", @list);
my @list = split "_XYZ_", $dbm{'key'};
2) 직렬화해주는 모듈 사용 - Data::Dumper, Storable, FreezeThaw 등
Storable 사용 예:
use POSIX;
use SDBM_File;
use Storable;
my %dbm;
my $db_file="demo.dbm";
tie %dbm, 'SDBM_File', $db_file, O_CREAT|O_RDWR, 0644;
$dbm{'key'}=Storable::freeze({Name=>"John", Value=>"Smith", Age=>"42"});
my $href=Storable::thaw($dbm{'key'});
my %hash=%{ Storable::thaw($dbm{'key'}) };
5. Multi-Level DBM (MLDBM)
일일이 프로그래머가 데이타를 직렬화하여 저장하고 읽어오는 것도 불편하다. [MLDBM]모듈을 사용하면 Perl에서 생성할 수 있는 어떤 데이타 구조도 저장가능하다.
사용법은 다른 DBM과 동일
use MLDBM;
use POSIX;
use strict;
my %mlhash;
my $mldb_file="mlanydbmdemo.dbm";
tie %mlhash, 'MLDBM', $mldb_file, O_CREAT|O_RDWR, 0644;
이 경우 MLDBM은 기본으로
- DBM은 SDBM을,
- 직렬화 모듈은 Data::Dumper를
사용한다. 이것은 성능이 좋지 못하다. MLDBM은 필요한 함수가 제공된다면 어떤 모듈을 써도 상관없다.
SDBM과 Storable을 사용하는 예
use SDBM_File;
use Storable;
use MLDBM qw(SDBM_File Storable);
AnyDBM File을 사용할 수도 있다
BEGIN {
@AnyDBM_File::ISA = qw(GDBM_File DB_File NDBM_File SDBM_File);
}
use AnyDBM_File;
use Storable;
use MLDBM qw(AnyDBM_File Storable);
복잡한 데이타를 저장하는 예
#!/usr/bin/perl
use MLDBM qw(SDBM_File Storable);
use POSIX;
use warnings;
use strict;
my %mldbm;
my $mldb_file="mldbmdemo.dbm";
tie (%mldbm, 'MLDBM', $mldb_file, O_CREAT|O_RDWR, 0644);
unless (tied %mldbm) {
print "Error opening $mldb_file: $!\n";
} else {
undef %mldbm;
$mldbm{'Created'}=localtime;
$mldbm{'AnonymousList'}=[1,2,3,4,"Five",6,7.8];
my @list=(9,"Ten",11,12.13,14);
$mldbm{'OriginalList'}=\@list;
$mldbm{'CopyOfList'}=[ @list ];
$mldbm{'NumberOfListElems'}=@list;
$list[0]="Nine";
$mldbm{'AnonymousHash'}={One=>'1',Two=>'2',Three=>'3'};
my %hash=(Four=>'4',Five=>'5',Six=>'6');
$mldbm{'OriginalHash'}=\%hash;
$mldbm{'CopyOfHash'}={ %hash };
$mldbm{'NumberOfHashKeys'}=keys %hash;
$hash{Four}="IV";
$mldbm{rand()}=rand;
$mldbm{'HashOfMixedValues'}={
List1=>[1,2,3],
List2=>[4,5,6],
String=>"A String",
Hash1=>{
A=>"a",
B=>"b",
Hash2=>{
C=>"c",
},
},
Number=>14.767,
List3=>[7,8,9],
};
foreach (sort keys %mldbm) {
print "$_ => $mldbm{$_}\n";
if (my $ref=ref $mldbm{$_}) {
if ($ref eq 'HASH') {
foreach my $key (sort keys %{ $mldbm{$_} }) {
print "\t$key => $mldbm{$_}{$key}\n";
}
} else {
print "\t",(join ",",@{ $mldbm{$_} }),"\n";
}
}
}
untie %mldbm;
}
- 해쉬나 리스트를 저장할 때는
- 원본 데이타에 대해 백슬래쉬 레퍼런스를 사용하거나
- 익명 해쉬, 익명 리스트 생성자 ({}, [])를 사용할 수 있다
- 이 때 MLDBM은 그 변수의 사본을 저장하므로, 원본 변수를 변경해도 DB에는 영향을 미치지 않는다
- MLDBM DB내의 데이타에 대한 레퍼런스를 만들어서 접근하더라도 그 레퍼런스는 tie된게 아니므로 DB의 값을 바꿀 수 없다. 오직 tie된 해쉬를 통해 최상위 레벨의 접근만이 올바르게 동작
- 리스트나 해쉬는 레퍼런스로 저장해야지, 그냥 쓰면 원소의 갯수가 저장된다.
7. comments
컴퓨터분류