データベース¶
リレーショナルデータベースにアクセスするには、使用したいデータベースサーバー用に設計された Shard が必要です。The package crystal-lang/crystal-db offers a unified api across different drivers.
次のパッケージ群は crystal-db に準拠しています。
- crystal-lang/crystal-sqlite3 for sqlite
- crystal-lang/crystal-mysql for mysql & mariadb
- will/crystal-pg for postgres
このガイドでは、crystal-db の API を紹介していますが、 postgres 、 mysql 、 sqlite の違いにより、具体的なドライバに合わせてsqlコマンドを変更する必要があるかもしれません。
また、いくつかのドライバーでは postgres の LISTEN
/NOTIFY
のように追加の機能を提供します。
shard のインストール¶
上のリストから適切なドライバを選択し、アプリケーションの shard.yml
に任意の shard を追加します。
crystal-lang/crystal-db
を明示的に追加する必要はありません。
このガイドを通して crystal-lang/crystal-mysql
を使用します。
dependencies:
mysql:
github: crystal-lang/crystal-mysql
データベースのオープン¶
DB.open
はコネクション uri を用いて容易なデータベースへの接続を提供します。uri のスキーマは期待されるドライバーを決定します。次のサンプルでは、root ユーザーを空パスワードで、 test という名前のローカルの mysql データベースに接続しています。
require "db"
require "mysql"
DB.open "mysql://root@localhost/test" do |db|
# ... クエリを実行するために db を利用します
end
その他の接続 uri です。
sqlite3:///path/to/data.db
mysql://user:password@server:port/database
postgres://server:port/database
あるいは、最後に Database#close
が呼ばれるまで終了しない yield を用いない DB.open
を使うこともできます。
require "db"
require "mysql"
db = DB.open "mysql://root@localhost/test"
begin
# ... クエリを実行するために db を利用します
ensure
db.close
end
実行¶
sql 文を実行するには Database#exec
を利用します。
db.exec "create table contacts (name varchar(30), age int)"
To avoid SQL injection values can be provided as query parameters.
クエリパラメータを使用するための構文はデータベースドライバに依存します。なぜならそれらは通常データベースに渡されるだけだからです。MySQL ではパラメータの展開に ?
を使用し、代入は引数の順序に基づいて行われます。PostgreSQL では $n
を使用し、 n
は1から始まる引数の順序です。
# MySQL
db.exec "insert into contacts values (?, ?)", "John", 30
# Postgres
db.exec "insert into contacts values ($1, $2)", "Sarah", 33
クエリ¶
クエリを実行し結果セットを得るために Database#query
を使用します。引数は Database#exec
と同様です。
Database#query
はクローズする必要のある ResultSet
を返します。Database#open
のように、 ブロックとともに呼び出した場合は、 ResultSet
は暗黙のうちにクローズされます。
db.query "select name, age from contacts order by age desc" do |rs|
rs.each do
# ... ResultSet の各行が実行される
end
end
データベースから値を読み込む際には、コンパイル時に crystal が使用できる型情報がありません。データベースから取得するとされるタイプ T
と共に rs.read(T)
を呼び出す必要があります。
db.query "select name, age from contacts order by age desc" do |rs|
rs.each do
name = rs.read(String)
age = rs.read(Int32)
puts "#{name} (#{age})"
# => Sarah (33)
# => John Doe (30)
end
end
最上位の #query
には、多くの便利なクエリメソッドが構築されています。
一度に複数の列を読み取ることが出来ます:
name, age = rs.read(String, Int32)
1行で読み取ることもできます:
name, age = db.query_one "select name, age from contacts order by age desc limit 1", as: {String, Int32}
また、ResultSet を明示的に取り扱わずにスカラ値を読み取ることもできます:
max_age = db.scalar "select max(age) from contacts"
データベース内で文を実行するためのすべての利用可能なメソッドは DB::QueryMethods
で定義されています。