Build Web Application With Golang を試してやってみる 17

はじめに

前回の記事の続きです。
前回の記事はこちら

database/sqlインターフェース

今回からは、データベースについてです。
Go のデータベースドライバがどのようなものかについての紹介のようですね。

GoがPHPと異なる部分は、Goには公式に提供されたデータベースドライバがない事です。
開発者が開発するためにデータベースドライバで標準のインターフェースが定義されています。

sql.Register

database/sqlに存在する関数はデータベースドライバを登録するためにあります。
サードパーティの開発者がデータベースドライバを開発する時は、すべてinit関数を実装します。
init関数ではこのRegister(name string, driver driver.Driver)をコールすることでこのドライバの登録を完了させます。

なるほど?

ドライバを登録して、この後使えるようにする処理という理解でOK?

driver.Driver

Driverはデータベースドライバのインターフェースです。methodがひとつ定義されています:
Open(name string)、このメソッドはデータベースのConnインターフェースを一つ返します。

データベースを開くような意味でしょうか。

サードパーティドライバはすべてこの関数を定義しています。
これはname引数を解析することによって目的のデータベースの接続情報を得ることができます。
解析が終わると、この情報を使って、ひとつのConnを初期化し、それを返します。

書いてありましたね、大体理解は良さそうです。

driver.Conn

Connはデータベース接続のインターフェース定義です。これにはいくつかのメソッドが定義されています。

聞いた感じコネクションですね。 インターフェースで、3つメソッドがありますね。

Prepare関数は現在の接続と関連した実行されるSQL文の準備状態を返します。検索、削除等の操作を行うことができます。
Close関数は現在の接続を閉じます。接続が持っているリソースを開放するなど整理作業を行います。ドライバはdatabase/sqlの中のconn poolを実現しているので、問題を起こしやすいのです。
Begin関数はトランザクション処理を表すTxを返します。これを利用して検索、更新といった操作を行うことができます。またはトランザクションに対してロールバックやコミットを行います。

おぉ~。よく見るDB操作の関数ですね。

driver.Stmt

Stmtは準備が整った状態です。
Connの関連性と、またひとつのgoroutineの中でしか使用することができません。複数のgoroutineに使用することはできません。

これは PHP, PDO とかでもある stmt と同じそうですね。
この後、execute でSQL実行とかできるのかな。

Close関数は現在の接続状態を閉じます。ただし、もし現在実行されているqueryはrowsデータを返します。
NumInput関数は現在予約されている引数の個数を返します。>=0が返された時はデータベースドライバがインテリジェントに使用側の引数を検査します。データベースドライバパッケージが予約された引数を知らない場合は-1を返します。
Exec関数はPrepareで準備の整ったsqlを実行します。引数を渡し、update/insertといった操作を実行します。Resultデータを返します。
Query関数はPrepareで準備の整ったsqlを実行します。必要な引数を渡し、select操作を実行します。Rowsリザルトセットを返します。

同じっぽいですね。
NumInput だけ聞き慣れないかも。

driver.Tx

トランザクション処理には一般的に2つのプロセスがあります。コミットかロールバックです。データベースドライバの中ではこの2つの関数を実装すれば問題ありません。

なるほど、トランザクションの操作ですね。
Tx - Rx(通信で使う用語)かと思ったので、driver.Rx ってあるのかなと思ったけど、
Transaction の略っぽいですね。(To -> 2 , For4 みたいなアレ)

driver.Execer

これはConnが実装できるインターフェースです。

Exec のメソッドだけありますね、 prepare=>stmt=>exec の流れはよく見ますね(PHPのPDO)

driver.Result

これはUpdate/Insertといった操作が行った結果を返すインターフェースの定義です。

結果を返したときの動きですね。

LastInsertId関数はデータベースによって実行された挿入操作によって得られるインクリメントIDを返します。
RowsAffected関数はquery操作で影響されるデータの数を返します。

LastInsertId は,登録した後にID を返したいとかの場合に使いますね!

driver.Rows

Rowsは実行された検索のリザルトセットのインターフェースの定義です

結果セットを返してくれるものですね!

Columns関数はデータベースの検索におけるフィールド情報を返します。これが返すsliceとsql検索のフィールドは一つ一つが対応しており、すべての表のフィールドを返すわけではありません。
Close関数はRowsイテレータを閉じるために用いられます。
Next関数はひとつのデータを返すのに用いられます。
データはdestに代入され、destの中の要素はstringを除いてdriver.Valueの値でなければなりません。
返されるデータの中のすべてのstringは[]byteに変換される必要があります。
もし最後にデータが無い場合、Next関数はio.EOFを返します。

dest []Value の中に入れられるんですね。

driver.RowsAffected

これはさっきと似てますね。

driver.Value

Valueは実は空のインターフェースです。どのようなデータも格納することができます。

これがさっきの driver.Rows にあった Value ですね。
何でも入れられる interface{} が実体ですね。

driver.ValueConverter

ValueConverterインターフェースはどのように普通の値をdriver.Valueのインターフェースの変換するか定義されています。

なるほど・・・?

driver.valueはデータベース表の対応するフィールドに特化されています。たとえばint64のデータがどのようにデータベース表のunit16フィールドに変換されるかといったことです。 データベースの検索結果をdriver.Value値に変換します。 scan関数ではどのようにしてdriver.Valueの値をユーザが定義した値に変換するか

カラムごとに型を変換してくれるということでしょうか、なるほど~!
どうやって型にはめていくのかと思ったのですが、こういうのがあるのですね。
型がない動的型付けの言語ですと、配列に入っていたりもしくは、Entity をつくって加工したものを入れたりなどがありますね。

driver.Valuer

Value() メソッドだけがありますね。
操作した後に、Value() を返すみたいなのをしてくれるようにするためのものですかね。

上の説明によって、ドライバの開発について基本的なことがお分かりいただけたかとおもいます。このドライバはただこれらインターフェースを実装して追加・削除・検索・修正といった基本操作を可能にするだけです。あとは対応するデータベースに対してデータをやりとりするなど細かい問題が残っています。ここでは細かく述べることはしません。

database/sql

database/sqlではdatabase/sql/driverにて提供されるインターフェースの基礎の上にいくつかもっと高い階層のメソッドを定義しています。データベース操作を容易にし、内部でconn poolを実装しています。

これが一番上にあるものですね。

Open関数がDBオブジェクトを返しています。この中にはfreeConnがあり、これがまさに簡単な接続プールのことです。この実装はとても簡単でまた簡素です。Db.prepareを実行する際defer db.putConn(ci, err)を行います。つまりこの接続を接続プールに放り込むのです。毎回connをコールする際はまずfreeConnの長さが0よりも大きいか確認し、0よりも大きかった場合connを再利用してもよいことを示しています。直接使ってかまいません。もし0以下であった場合はconnを作成してこれを返します。

コネクションプールってやつですね。
つながっているコネクションを再利用するみたいなやつ(曖昧)

ここまでざっと読みましたが、やはり使ってみないとわかりません!
というわけで明日から MySQLデータベースの使用 ですね。
Docker の環境ですが、明日つくってその記事にします。

おわりに

おやすみなさい。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。