LoginSignup
8
5

More than 5 years have passed since last update.

ScalikeJDBC 3.0 コードリーディング(コネクション関係)

Posted at

1. はじめに

 これは、私がScalaを勉強している過程で、オープンソースのコードを読んでみようと思い、色々調べた事を記載しています。私は、これまでまともにオープソースのコードを読んでおらず、業務でもプログラミンをほぼ書かなくなっている者です。が、なるべく初心者でもソースコードを読むきっかけになればと思い書きました。ScalikeJDBCを選択したのは、元々ドキュメントが充実しており、簡単なサンプルアプリなら作ることが出来たので、中身に興味を持てたためです。興味は持てたのですが、なかなか理解出来ない書き方等があり、苦労もありましたが、読む事がScalaの理解にも繋がりました。まずは、主要なクラスの紹介から入って、細かいところで気付いた箇所を説明したいと思います。

以下からコードを幾つか参照させていただいています。
https://github.com/scalikejdbc/scalikejdbc

2. コネクション

 object のDB が主要クラスとなります。DBは、trait である DBConnectionを継承しています。DBConnection は、LogSupport、LoanPattern、AutoCloseableを継承しており、java.sql.Connectionの管理を担当しています。が、DBを通じて、DBConnectionの関数を呼び出しています。
connection_1.jpg

DBのメソッドを簡単に紹介します。

メソッド 概略
readOnly 『DBSessionを受け取りAを返す関数』を引数に取る。読み取り専用の処理。
autoCommit 同上で、コミット(ロールバック)を自動的に実施。
localTx 同一ブロックのSQLを同一トランザクション管理できます。失敗すれば全てロールバック。
futureLocalTx Futureでラップした結果を受け取り、それぞれの処理をひとつのトランザクションとして管理します。
withinTx 呼び出す側にてトランザクション管理(begin,commit/rollback)が必要です。

他にも、getAllColumnsやgetColumnNames、getTableと言ったメソッドも持っている。

親のtrait である DBConnection がjava.sql.Connectionを保持していますが、その取得は点線で下にひも付けている、ConnectionPoolContextを利用しています(ScalikeJDBCのコネクションプールは後述)。
このDBConnectionもreadOnly、autoCommit等々と同名のメソッドを持っています。大きな違いは、implicit パラメータが無いところです。また、readOnlyの中では『DBSessionを引数に持ち、A を返す』関数が実行されます。

DB.scala(object)


  /**
   * Begins a read-only block easily with ConnectionPool.
   *
   * @param execution execution
   * @param context connection pool context
   * @tparam A return type
   * @return result value
   */
  def readOnly[A](execution: DBSession => A)(implicit context: CPContext = NoCPContext, settings: SettingsProvider = SettingsProvider.default): A = {
    val cp = connectionPool(context)
    using(cp.borrow()) { conn =>
      DB(conn, cp.connectionAttributes, settings).autoClose(false).readOnly(execution)
    }
  }
DBConnection.scala

  /**
   * Provides read-only session block.
   * @param execution block
   * @tparam A  return type
   * @return result value
   */
  def readOnly[A](execution: DBSession => A): A = {
    if (autoCloseEnabled) using(conn)(_ => execution(readOnlySession()))
    else execution(readOnlySession())
  }

この『DBSessionを受け取る関数』を引き渡しているところは、他のメソッドでも見られる特徴です。このおかげで、以下に記載があるように、お決まりの長い記述をコーディングしなくても済んでいます。
http://scalikejdbc.org/documentation/connection-pool.html

3. コネクションプール

コネクションプールに関しては、サンプルにあるようにConnectionPoolのsingletonで初期化が走ります。実際には内部でaddが呼ばれて初期化が色々走っています。
当初は、XXXXPoolクラスが沢山あって、ポイントが理解できなかったのですが、『ConnectionPoolのフレームワーク』が色々存在して、それを隠蔽する形で利用できるようにしてある事が理解できれば、すんなりわかった気がします。

connectionpool_1.jpg

デフォルトは、commons-dbcp2ですが、他のサイトで確認していると、HikariCPが圧倒的に処理量が多いとの記載がありました(が実際に確認はできていませんのでご注意下さい)。

4. 気付いたところ

読んでいて気づきがあったところを書いてみたいと思います。

メソッドの最後のthis

最初読み始めた時は、setterっぽいメソッドでどうして最後にthisを返すのか、意味がわかっていませんでした。

DBConnection.scala
  /**
   * Switches auto close mode.
   * @param autoClose auto close enabled if true
   */
  def autoClose(autoClose: Boolean): DBConnection = {
    this.autoCloseEnabled = autoClose
    this
  }

これは、以下の様に文章の様にコーディングするためだとようやく気づく事ができました。


DB(conn, cp.connectionAttributes, settings).autoClose(false).readOnly(execution)

Scala 本体のコードでも見ることができる書き方です。

Vector.scala
  override def takeRight(n: Int): Vector[A] = {
    if (n <= 0)
      Vector.empty
    else if (endIndex - n > startIndex)
      dropFront0(endIndex - n)
    else
      this
  }

=> ロケットシンボル

match case だとか、関数リテラルだとかは理解出来ているつもりだったのですが、以下の構文はすぐにはピンと来ませんでした。

DBConnection.scala
  /**
   * Provides read-only session block.
   * @param execution block
   * @tparam A  return type
   * @return result value
   */
  def readOnlyWithConnection[A](execution: Connection => A): A = {
    readOnly(s => execution(s.conn))
  }

ずっと s を探していました。。。どこで渡されるんだろうって。
これも関数リテラルで、『DBSessionを受け取る関数』をパラメータにして、readOnlyを呼んでいる事が理解できて、ようやく読めた気がしました。
以下みたいに、型と()を記述して、少し納得できました。

readOnly((s: DBSession) => execution(s.conn))

クラス図は意外に大事

今まであまりソースコードをしっかり読んで来なかったので、ファイルがずらっと並んでいてもずっとモヤモヤしてました。処理を追っていって頭では理解できたつもりでも、もう一度見直すとモヤモヤ感からやり直しの日々でした。
それから抜け出すために、図に書きだして見ると、まずはその図が頭に浮かぶようになりました。自分はやはり図からコードをイメージするタイプなようです。
今回、書いた図(とこの文章)が初めてScalikeJDBCのソースコードを読む人の少しでも手助けになればと思います。
あと、次は"SQL"まわりの理解にチャレンジします。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5