アマゾンAPIを活用した蔵書管理システム(3)
November 18, 2008 – 5:36 pm前回までのエントリで、アマゾンAPIを利用して書籍データを取得する仕組みを整えることができた。いよいよ、アマゾンから取得した書籍データを我がサーバ上にデータベースとして取り込む方法について移る。データベース化にあたっては、以前のエントリ「MySQLを学習(1)」において学んだリレーショナルデータベースの利点を実際に体験することになる。
データベースの設計と構築: 私のようにDBMSの初心者にとって本格的なデータベースをいちから設計するというのは骨の折れる仕事だ。そこで、Web上で紹介されている蔵書データベースにどのようなものがあるか調べることから始めた。そこで見つけたのが、「蔵書インデキシングプロジェクト活動進捗(4)」に述べられている労作。なるほど、データベースの正規化というのはこのように行うのかと感心。ということで、ここで示されているデータベース構造を借用させていただいて、蔵書データベースとすることにした。(若干、我がほうに都合のよいように変更した部分もあるが、基本的な構造はquneさんのブログの記述を活用させていただいた。感謝)
DBテーブル作成用のSQL文は以下:
BookDB.sql:
DROP TABLE IF EXISTS book_author; DROP TABLE IF EXISTS book; DROP TABLE IF EXISTS publisher; DROP TABLE IF EXISTS binding; DROP TABLE IF EXISTS role; DROP TABLE IF EXISTS currency; DROP TABLE IF EXISTS author; CREATE TABLE publisher ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, publisher VARCHAR(256) NOT NULL ); CREATE TABLE binding ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, binding VARCHAR(64) NOT NULL ); CREATE TABLE role ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, role VARCHAR(32) NOT NULL ); CREATE TABLE currency ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, currency_cd CHAR(3) NOT NULL ); CREATE TABLE author ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, author VARCHAR(64) NOT NULL ); CREATE TABLE book ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, isbn CHAR(10), asin CHAR(10), ean CHAR(13), title VARCHAR(256) NOT NULL, image_url VARCHAR(128), pubdate DATE, price DECIMAL(10,2), pages INTEGER(6), publisher_id INTEGER(8), binding_id INTEGER(8), currency_id INTEGER(8) ); ALTER TABLE book ADD FOREIGN KEY (publisher_id) REFERENCES publisher (id); ALTER TABLE book ADD FOREIGN KEY (binding_id) REFERENCES binding (id); ALTER TABLE book ADD FOREIGN KEY (currency_id) REFERENCES currency (id); CREATE TABLE book_author ( id INTEGER(8) PRIMARY KEY AUTO_INCREMENT, book_id INTEGER(8) NOT NULL, author_id INTEGER(8) NOT NULL, role_id INTEGER(8) ); ALTER TABLE book_author ADD FOREIGN KEY (book_id) REFERENCES book (id); ALTER TABLE book_author ADD FOREIGN KEY (author_id) REFERENCES author (id); ALTER TABLE book_author ADD FOREIGN KEY (role_id) REFERENCES role (id)
データベース作成の手続き: ここで示したSQL文に基づきデータベース作成の手続きを示すことにしよう。なお、データベース作成手順については、既に我がブログの以前のエントリー「MySQLを学習(2):DataBaseとTableの作成」において記述しており、これと重複する部分があることをお断りしておく。
まず、「蔵書管理システム」用の空のデータベースSampleDBを作成する:
# mysql -u username -p Enter password: password Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9994 Server version: 5.0.45 Source distribution Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> create database sampleDB; Query OK, 1 row affected (0.00 sec)
このDB上に、既に述べたBookDB.sql で定義した複数のテーブルを一括して作成する:
# mysql -u username -p SampleDB < BookDB.sql; Enter password: password
これで、データベースSampleDBの枠組みが出来上がったはずだ。実際に、テーブルが問題なく作成されていることを確かめてみよう;
# mysql -u username -p SampleDB Enter password: password mysql> show tables; +--------------------+ | Tables_in_SampleDB | +--------------------+ | author | | binding | | book | | book_author | | currency | | publisher | | role | +--------------------+ 7 rows in set (0.00 sec) mysql> describe book; +--------------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+---------------+------+-----+---------+----------------+ | id | int(8) | NO | PRI | NULL | auto_increment | | isbn | char(10) | YES | | NULL | | | asin | char(10) | YES | | NULL | | | ean | char(13) | YES | | NULL | | | title | varchar(256) | NO | | | | | image_url | varchar(128) | YES | | NULL | | | pubdate | date | YES | | NULL | | | price | decimal(10,2) | YES | | NULL | | | pages | int(6) | YES | | NULL | | | publisher_id | int(8) | YES | MUL | NULL | | | binding_id | int(8) | YES | MUL | NULL | | | currency_id | int(8) | YES | MUL | NULL | | +--------------+---------------+------+-----+---------+----------------+ 12 rows in set (0.00 sec) mysql> describe author; +--------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+----------------+ | id | int(8) | NO | PRI | NULL | auto_increment | | author | varchar(64) | NO | | | | +--------+-------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> describe book_author; +-----------+--------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------+------+-----+---------+----------------+ | id | int(8) | NO | PRI | NULL | auto_increment | | book_id | int(8) | NO | MUL | | | | author_id | int(8) | NO | MUL | | | | role_id | int(8) | YES | MUL | NULL | | +-----------+--------+------+-----+---------+----------------+ mysql> quit; Bye
書籍データのデータベース上への反映: データベースの枠組みが完成したところで、前回のエントリーで紹介した方式で取得する書籍データを、このデータベース上に反映させなければならない。前回説明したように、取得データは、個々の書籍について2種類のデータオブジェクト(DTO形式:Book、Author_array)で得られる。次の作業は、これらDTO形式のデータを上記したSQLデータベースSampleDBに取り込むための仕組みを作成することになる。
SampleDBへのデータの取り込みを行うため、Daoオブジェクト(BookDao)を作成し、このなかに、新規の書籍データを取り込むためのメソッドinsertBook()を作成した。BookDaoのphpソースは最後に掲げることにし、実際に、これを用いて書籍データをデータベースに登録する手続きをサンプルとして以下にしめしてみよう:
サンプルでは、前回のエントリーで取り扱った本「利己的な遺伝子」をデータベース上に取り込むことにする。そのためのSample.phpを作成する:
Sample.php
<?php require_once("SetBookByBookID.php"); require_once("BookDao.php"); $BOOK_ID = '4314005564'; $BookCode = 'ISBN'; $rtn = SetBookByBookID($BOOK_ID, $BookCode); $book = $rtn[0]; $author_array = $rtn[1]; $bookdao = new BookDao(); $bookdao->insertBook($book, $author_array); $book = NULL; $author_array = NULL; $bookdao = NULL; ?>
このphpスクリプトでは、まず前回作成したSetBookByBookID()を用いて書籍データを二つのデータオブジェクト$bookと$author_arrayで取得する。このデータを新たに作成したクラスBookDaoのメソッドinsertBook()の引数とし、これによりSampleDB上に反映している。
この方法で9冊の書籍を、逐次、データベースSampleDB上に取り込み、SampleDB上にデータが正しくとりこまれていることを確認してみた。
mysql> select id, title from book; +----+-----------------------------------------------------------------------------------------------+ | id | title | +----+-----------------------------------------------------------------------------------------------+ | 1 | 利己的な遺伝子 (科学選書) | | 2 | 盲目の時計職人 | | 3 | はじめての年金・医療保険―保険の基本は社会保険から (集英社新書) | | 4 | 科学者の新しい役割 (双書科学/技術のゆくえ) | | 5 | 第二種基礎研究 | | 6 | 免疫の意味論 | | 7 | 公共のための科学技術 | | 8 | 生態学的視覚論―ヒトの知覚世界を探る | | 9 | 「病気」の誕生―近代医療の起源 (平凡社選書) | +----+-----------------------------------------------------------------------------------------------+ 9 rows in set (0.00 sec) mysql> select id, author from author; +----+-----------------------------------+ | id | author | +----+-----------------------------------+ | 1 | リチャード・ドーキンス | | 2 | 日高 敏隆 | | 3 | 岸 由二 | | 4 | 羽田 節子 | | 5 | 垂水 雄二 | | 6 | 児玉 美穂 | | 7 | 吉川 弘之 | | 8 | 内藤 耕 | | 9 | 多田 富雄 | | 10 | 小林 伝司 | | 11 | J.J.ギブソン | | 12 | 古崎 敬 | | 13 | 児玉 善仁 | +----+-----------------------------------+ 13 rows in set (0.00 sec) mysql> select id, role from role; +----+--------+ | id | role | +----+--------+ | 1 | | | 2 | 翻訳 | | 3 | 編集 | +----+--------+ 3 rows in set (0.00 sec) mysql> select * from book_author; +----+---------+-----------+---------+ | id | book_id | author_id | role_id | +----+---------+-----------+---------+ | 1 | 1 | 1 | 1 | | 2 | 1 | 2 | 2 | | 3 | 1 | 3 | 2 | | 4 | 1 | 4 | 2 | | 5 | 1 | 5 | 2 | | 6 | 2 | 1 | 1 | | 7 | 2 | 2 | 2 | | 8 | 3 | 6 | 1 | | 9 | 4 | 7 | 1 | | 10 | 5 | 7 | 1 | | 11 | 5 | 8 | 1 | | 12 | 6 | 9 | 1 | | 13 | 7 | 10 | 3 | | 14 | 8 | 11 | 1 | | 15 | 8 | 12 | 1 | | 16 | 9 | 13 | 1 | +----+---------+-----------+---------+ 16 rows in set (0.00 sec) mysql> select id, publisher from publisher; +----+-----------------------+ | id | publisher | +----+-----------------------+ | 1 | 紀伊國屋書店 | | 2 | 早川書房 | | 3 | 集英社 | | 4 | 岩波書店 | | 5 | 日経BP社 | | 6 | 青土社 | | 7 | 玉川大学出版部 | | 8 | サイエンス社 | | 9 | 平凡社 | +----+-----------------------+ 9 rows in set (0.00 sec)
テーブル上に書き込まれたデータが想定した通りデータベース上にあることが確認される。なお、アマゾンの書籍データベースへのアクセスは1秒に1回の制限があることから、アマゾンからの書籍データ取り込み用関数SetBookByBookID()を使用する際に注意したい。
さて、これでデータベースへの書籍データの取り込みは行うことができた。次回は、今回作成したSampleDBからのデータのk検索など、その操作方法についてみることにしよう。
BookDao.php:
<?php Class BookDao { private $mysqli = null; //Constructor function __constructor() { $this->connect(); } //Destructor function __destruct() { $this->disconnect(); } //Connect to MySQL server private function connect() { if(is_null($this->mysqli)) { $this->mysqli = new mysqli("localhost", "user_name", "password", "SampleDB"); $this->mysqli->query("SET NAMES utf8"); if(mysqli_connect_errno()) { die("Failed to connect to MySQL server<br></br> Reason:" . mysqli_connect_error()); } } } //Disconnect from MySQL server private function disconnect() { is_null($this->mysqli) or $this->mysqli->close(); } // Register New Book_Data for tables public function insertBook( $book, $author_array ) { is_null($this->mysqli) and $this->connect(); // check book to be registered in Table Book $sql = "SELECT id FROM book WHERE asin='". $book->getAsin() . "'"; $result = $this->mysqli->query($sql); if ( $result->num_rows != 0 ) { $row = $result->fetch_array(MYSQLI_ASSOC); echo "This book is already registered! \n"; $book_id = $row["id"]; echo "book_id registered = " . $book_id . "\n" ; } else { // Set publisher table and publisher_id $sql = "SELECT id FROM publisher WHERE publisher='" . $book->getPublisher() . "'"; $result = $this->mysqli->query($sql); if ( $result->num_rows == 0 ) { $sql = "INSERT INTO publisher values('', '" . $book->getPublisher() . "')"; if (!$this->mysqli->query($sql)) { print "Failed to register(1002) " . $this->mysqli->error . "\n"; } else { $publisher_id = $this->mysqli->insert_id; } } else { $row = $result->fetch_array(MYSQLI_ASSOC); $publisher_id = $row["id"]; } // Set binding table and binding_id $sql = "SELECT id FROM binding WHERE binding='" . $book->getBinding() . "'"; $result = $this->mysqli->query($sql); if ( $result->num_rows==0 ) { $sql = "INSERT INTO binding values('', '" . $book->getBinding() . "')"; if (!$this->mysqli->query($sql)) { print "Failed to register(1003) " . $this->mysqli->error . "\n"; } else { $binding_id = $this->mysqli->insert_id; } } else { $row = $result->fetch_array(MYSQLI_ASSOC); $binding_id = $row["id"]; } // Set currency table and currency_id $sql = "SELECT id FROM currency WHERE currency_cd='" . $book->getCurrency_cd() ."'"; $result = $this->mysqli->query($sql); if ( $result->num_rows == 0 ) { $sql = "INSERT INTO currency VALUES('', '" . $book->getCurrency_cd() . "')"; if (!$this->mysqli->query($sql)) { print "Failed to register(1004) " . $this->mysqli->errro . "\n"; } else { $currency_id = $this->mysqli->insert_id; } } else { $row = $result->fetch_array(MYSQLI_ASSOC); $currency_id = $row["id"]; } // Set Book Table for new data $sql = "INSERT INTO book values('', '" . $book->getIsbn() . "', '" . $book->getAsin() . "', '" . $book->getEan() . "', '" . $book->getTitle() . "', '" . $book->getImage_url() . "', '" . $book->getPubdate() . "', '" . $book->getPrice() . "', '" . $book->getPages() . "', '" . $publisher_id . "', '" . $binding_id . "', '" . $currency_id . "')"; if( !$this->mysqli->query($sql) ) { print "Failed to register(1005) " . $this->mysqli->error . "\n"; } else { $book_id = $this->mysqli->insert_id; } // Set Author Table for new data for ( $i=0; $i<sizeof($author_array); $i++) { $sql = "SELECT id FROM author where author='" . $author_array[$i]->getAuthor() . "'"; $result = $this->mysqli->query($sql); if ( $result->num_rows == 0 ) { $sql = "INSERT INTO author values('', '" . $author_array[$i]->getAuthor() . "')"; if(!$this->mysqli->query($sql)) { print "Failed to register(1006) " . $this->mysqli->error . "\n"; } else { $author_id = $this->mysqli->insert_id; } } else { $row = $result->fetch_array(MYSQLI_ASSOC); $author_id = $row["id"]; } $sql = "SELECT id FROM role where role='" . $author_array[$i]->getRole() . "'"; $result = $this->mysqli->query($sql); if ( $result->num_rows == 0 ) { $sql = "INSERT INTO role values('', '" . $author_array[$i]->getRole() . "')"; if(!$this->mysqli->query($sql)) { print "Failed to register(1007) " . $this->mysqli->error . "\n"; } else { $role_id = $this->mysqli->insert_id; } } else { $row = $result->fetch_array(MYSQLI_ASSOC); $role_id = $row["id"]; } $sql = "INSERT INTO book_author values('', '" . $book_id . "','" . $author_id . "','" . $role_id . "')"; if( !$this->mysqli->query($sql) ) { print "Failed to register(1008) " . $this->mysqli->error . "\n"; } } } } } ?>
1 Trackback(s)