# DBI

DBI는 데이터베이스에 독립적인 프로그래밍 인터페이스입니다.

```bash
sudo cpanm DBI
```

[DBI - Database independent interface for Perl - metacpan.org](https://metacpan.org/pod/DBI)

## DBD

데이터베이스 드라이버입니다.

```bash
sudo cpanm DBD::xxx
```

- DBD::MariaDB

  ```bash
  sudo apt install libmariadb-dev # 모듈 설치시에 필요합니다.
  sudo cpanm DBD::MariaDB
  ```

- DBD::Pg

- DBD::SQLite

- DBD::Oracle

- DBD::CSV

- DBD::RAM

- DBD::JDBC

- DBD::ODBC


```perl
use DBI;

my @driver_names = DBI->available_drivers;

foreach(@driver_names){
    print "$_\n";
}
```

## 데이터베이스 연결

```perl
# SQLite
my $dsn = "DBI:SQLite:dbname=$dbFile";
my $dbh = DBI->connect($dsn, $dbUsername, $dbPassword);
```

https://metacpan.org/pod/DBD::SQLite

```perl
# MariaDB
my $dsn = "DBI:MariaDB:database=$database;host=$hostname;port=$port";
my $dbh = DBI->connect($dsn, $dbUsername, $dbPassword);
```

https://metacpan.org/pod/DBD::MariaDB

`connect`에 4번째 매개 변수로 자동 커밋 등의 옵션을 지정할 수 있습니다.

```perl
my $dbh = DBI->connect('DBI:SQLite:dbname=$dbFile', undef, undef, {
  AutoCommit => 1, # 자동 커밋을 사용하도록 지정합니다.
  RaiseError => 1 # 오류 처리를 자동으로 하도록 지정합니다.
});
```

## 그래서, 샘플

```perl
#!/usr/bin/perl
use warnings;
use strict;
use DBI;

my $dbFile = 'test.db';
my $dbUsername = '';
my $dbPassword = '';

# 데이터베이스에 연결
my $dbh = DBI->connect("DBI:SQLite:dbname=$dbFile", $dbUsername, $dbPassword);


my $table = 'test';
# 간단한 SQL 실행에는 do를 사용합니다. - 테이블 생성
my $sth = $dbh->do("CREATE TABLE IF NOT EXISTS $table (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);");

# 삽입
$sth = $dbh->prepare("INSERT INTO $table (name, age) VALUES (?,?);");
$sth->execute('Charlie', 13);
$sth->execute('Steve', 34);
$sth->execute('Mary', 34);
$dbh->commit() or die $DBI::errstr;

# 조회
$sth = $dbh->prepare("SELECT * FROM $table WHERE age=?;");
$sth->execute(34);
while(my @row = $sth->fetchrow_array()){
    my ($id, $name, $age) = @row;
    print "$id | $name | $age\n";
}

# 연결 끊기
my $rc = $dbh->disconnect  or warn $dbh->errstr;
```

### 조회 결과를 바인딩

`fetch`를 `bind_columns`와 함께 사용하면 빠르게 결과값을 처리할 수 있습니다.

```perl
$sth = $dbh->prepare("SELECT * FROM $table WHERE name=?;");
$sth->execute('Charlie');
my ($id, $name, $age);
$sth->bind_columns(\$id, \$name, \$age);
while($sth->fetch()){
    print "$id | $name | $age\n";
}
```

`fetchrow_hashref`는 해시에 대한 참조를 반환합니다. `fetch`보다는 다소 느립니다.

```perl
$sth = $dbh->prepare("SELECT * FROM $table WHERE name=?;");
$sth->execute('Steve');
while(my $row = $sth->fetchrow_hashref()){
    print "$row->{id} | $row->{name} | $row->{age}\n";
}
```

## 메서드

### 데이터베이스 핸들

- `do`

- `prepare` SQL 구문 핸들을 반환합니다.

- `commit`

- `last_insert_id`

- `begin_work` 자동 커밋을 중단하고 트랜잭션을 시작합니다.

- `rollback` 커밋되지 않은 동작을 되돌립니다.

- `disconnect`


### 스테이트먼트 핸들

- `execute` SQL을 실행합니다.

- `last_insert_id`

- `fetchrow_array` 조회 결과의 다음 행을 배열로 반환합니다.

- `fetch` = `fetchrow_arrayref` 조회 결과의 다음 행을 배열 참조로 반환합니다.

- `fetchrow_hashref`

- `bind_columns`

- `rows`

- `finish`

- `dump_results`