Common Lisp用のデータベースライブラリ「CL-DBI」を作りました
Common Lisp用のデータベースライブラリ「CL-DBI」を作りました。
https://github.com/fukamachi/cl-dbi
このエントリではCL-DBIの紹介と、なぜ新しくライブラリを作ろうと思ったかについて書こうと思います。
Common Lispが抱えるDB周りの問題
今までCommon LispでWebアプリケーションを作る際、毎回困るのはデータベースの扱いでした。ClackやCavemanで軽量なWebアプリケーションを作っても、手頃なDBライブラリがなく、素早いWeb開発のネックとなっていました。
おそらく最も使われているライブラリはCLSQLですが、安定性には疑問があります。具体的には以下のような問題がありました。
- 環境によってはうまくロードできないことが多い (特にSBCL)
- 裏側のデータベースの差異を抽象化しきれていない (SQLite3でうまく動かない機能がありハマることが多い)
- CLOSインタフェースを採用しており、APIがリッチすぎる
- フォークしようにも巨大な上、UFFIを使っているなど設計が古くてメンテナンスの継続が難しい
次によく使われているだろうElephantは、そもそもオブジェクトストアなので目的としていることが違うのですが、MySQLに対応してなかったり、保存するレコードの可読性が悪かったり、BerkleyDBでないとパフォーマンスが落ちてしまったり、何よりメンテナンスされてないという致命的な問題があります。
一方で、もっとシンプルなcl-mysqlなどを使うと、今度はアプリケーションがMySQLに依存してしまうことになります。開発時にはSQLite3を使い、デプロイ時にMySQLに切り替える、といった開発手法もできなくなります。
CL-DBIが解決すること
これを解決するために、CL-DBIを作りました。あくまで裏側のデータベース間の差異のみを吸収するシンプルなインタフェースを保っています。現在はSQLite3、MySQL、PostgreSQLのみ対応しています。
主な機能は以下です。
設計はPerlやGaucheのDBI/DBDを参考にしています。
CLSQLのようにCREATE TABLEなどを実行する機能はないです。つける予定もありません。
使い方
先ほど完成したばかりなのでまだQuicklispには取り込まれていません。試すにはまずGitHubからcloneします。
$ git clone https://github.com/fukamachi/cl-dbi.git
ASDFでロードします。
(asdf:load-system :dbi)
以下のように使えます。
;; MySQLの「test」に接続 (defvar *db* (dbi:connect :mysql :database-name "test" :username "nobody" :password "1234")) ;; prepare => execute (let ((query (dbi:prepare *db* "SELECT * FROM somewhere WHERE flag = ? OR updated_at > ?")) (result (dbi:execute query 0 "2011-11-01"))) ;; fetchで順番に結果を取り出す。 ;; rowはProperty List形式。 (loop for row = (dbi:fetch result) while row ;; process "row". )) ;; トランザクション ;; rollbackしなければ自動でcommitが呼ばれる。 (with-transaction *db* (do-sql *db* "INSERT INTO person (id, name) VALUES (2, 'm2ym')") (rollback *db*))
簡単でしょ?