Python でデータベース周りについて調べていると、ドキュメントの中にちょくちょく DB-API (2.0) という単語が出てくる。 果たしてこの DB-API とは何者なのか、というのが今回の主題。
結論から言ってしまうと、DB-API というのは Python でリレーショナルデータベースを操作するために定義された API の仕様を指している。 仕様というのがポイントで、これは具体的な実装を指しているわけではない。 DB-API は Python に関する仕様を決める PEP という枠組みの中で PEP0249 というドキュメントに書かれている。
PEP 249 -- Python Database API Specification v2.0 | Python.org
なぜ DB-API が必要になるのだろうか? それは、リレーショナルデータベースに SQLite3 や MySQL など、数々の実装がある点から説明できる。 それらは SQL を扱うリレーショナルデータベースという点で共通しているにも関わらず、それを操作するためのモジュールがそれぞれバラバラに API を決めていてはユーザにとって利便性が低くなる。 そこで登場するのが DB-API という仕様で、モジュールが仕様を満たすように作られることで、ユーザは使っているリレーショナルデータベースとモジュールに関わらず同じインターフェースを通して操作できるようになる
ここからは実際に色々なデータベース操作用モジュールで DB-API を触ってみることにする。 環境には Mac OS X を使っている。
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.11
BuildVersion: 15A284
SQLite3 (sqlite3)
まずは Python 組み込みの SQLite3 モジュールから。 組み込みなので Python さえ入っていれば特に何をするでもなく使うことができる。
Python の REPL を使って動作を確認していく。 インポートは sqlite3 という名前でできる。
$ python -q
>>> import sqlite3
例えば DB-API では apilevel や threadsafety といったグローバル変数が定義されている。
>>> sqlite3.apilevel '2.0' >>> sqlite3.threadsafety 1
また、データベースへの接続は connect() 関数を使うことになっている。
>>> sqlite3.connect
<built-in function connect>
たしかに DB-API 2.0 が実装されているようだ。
MySQL (PyMySQL)
次は MySQL 用のモジュールとして PyMySQL を試してみる。
Homebrew で MySQL をインストールした上で pymysql を入れる。
$ brew install mysql $ pip install pymysql
モジュールは pymysql という名前でインポートできる。 次のように、やはり別のモジュールであっても DB-API の仕様に則って同じグローバル変数、同じ関数が実装されている。
$ python -q >>> import pymysql >>> pymysql.apilevel '2.0' >>> pymysql.threadsafety 1 >>> pymysql.connect <function Connect at 0x100b44400>
Postgresql (psycopg2)
次は Postgresql 用のモジュール psycopg2 を試してみる。
Homebrew で Postgresql をインストールした上で、psycopg2 を入れる。
$ brew install postgresql $ pip install psycopg2
モジュールは psycopg2 という名前でインポートできる。 やはり、このモジュールも DB-API に則って必要なグローバル変数と関数が用意されている。 しかし、先のふたつとは threadsafety の値が異なっていることもわかる。
$ python -q >>> import psycopg2 >>> psycopg2.apilevel '2.0' >>> psycopg2.threadsafety 2 >>> psycopg2.connect <function connect at 0x10bd6d598>
DB-API を使ってみる
次は実際に DB-API を使ってみることにする。 リレーショナルデータベースには MySQL を使う。
動作確認用のデータベースとテーブルを作って行をひとつ追加しておく。
$ mysql.server start $ mysql -u root mysql> create database if not exists test; Query OK, 1 row affected, 1 warning (0.00 sec) mysql> use test; Database changed mysql> create table users ( -> id Integer auto_increment, -> name Text not null, -> primary key (id) -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into users (name) values ("foo"); Query OK, 1 row affected (0.00 sec) mysql> quit Bye
次に、Python の DB-API 経由で行を取得してみる。 connect() 関数でデータベースへの接続を確立したら、cursor() でカーソルオブジェクトを取得する。 カーソルオブジェクト経由で SQL を実行して結果を取得する。
$ python -q >>> import pymysql >>> connection = pymysql.connect('localhost', user='root', db='test') >>> with connection.cursor() as cursor: ... sql = 'select `id`, `name` from `users` where `name`=%s' ... cursor.execute(sql, 'foo') ... result = cursor.fetchone() ... print(result) ... 1 (1, 'foo')
ばっちり。
使い終わったらコネクションを閉じる。
>>> connection.close()
まとめ
今回は Python の DB-API について調べてみた。 DB-API は Python でリレーショナルデータベースを扱うモジュールに求められる仕様のことで、巷のモジュールはそれを実装している。 とはいえ、実際に Python でリレーショナルデータベースを扱う際には、インピーダンスミスマッチの問題があるので SQL を直接発行するような低レベルの DB-API を直接使う場面というのは少ないと思う。 現実的には O/R マッパー (例えば SQLAlchemy など) が内部的に DB-API を使うことで、間接的にその恩恵に預かることになるだろう。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る