0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

Transactorで接続する

データベースへのアクセスを設定します。

「Transactorで接続する」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

Transactorとは

DoobieはScala向けの純粋関数型JDBCレイヤーです。Transactor[F]は、Doobieの純粋なプログラムと実際のデータベース接続を橋渡しします。

Transactorは、JDBCのConnectionを取得し、プログラムをトランザクション内で実行して、安全にリソースを解放する方法を把握しています。

これはcats.effect.IOなどのエフェクト型F[_]でパラメーター化されています。

import doobie._
import cats.effect.IO

val xa: Transactor[IO] = ???

ConnectionIOプログラム

DoobieのクエリはConnectionIO[A]型の値です。これはJDBC接続を必要とする計算を表しますが、まだ実行はされません。

これらのプログラムを純粋に構築し、Transactorに渡して実行します。実行するまでデータベースには何も触れません。

import doobie.implicits._

val program: ConnectionIO[Int] =
  sql"select 42".query[Int].unique

DriverManagerTransactor

最も単純なTransactorはTransactor.fromDriverManagerです。JDBCのDriverManagerを使い、トランザクションごとに新しい接続を開きます。

ドライバークラス名、JDBC URL、ユーザー名、パスワードが必要です。テストやスクリプトには適していますが、接続プールはありません。

val xa = Transactor.fromDriverManager[IO](
  driver = "org.postgresql.Driver",
  url = "jdbc:postgresql://localhost:5432/app",
  user = "postgres",
  password = "secret",
  logHandler = None
)

プログラムの実行

ConnectionIOを実行するには.transact(xa)を呼び出します。これにより、ここではIO[A]であるF[A]が得られます。

Transactorはプログラムをトランザクションでラップします。成功時にはコミットし、失敗時にはロールバックし、どちらの場合も接続を解放します。

import doobie.implicits._

val result: IO[Int] =
  sql"select 42".query[Int].unique.transact(xa)

HikariCPによるプール

本番環境では接続プールが必要です。Doobieには、HikariCPを基盤とするHikariTransactorが用意されています。

これはResourceとして作成されるため、プールを適切にシャットダウンできます。また、ブロッキングするJDBC操作用の実行コンテキストも渡します。

import doobie.hikari.HikariTransactor
import cats.effect.IO

val xaRes: Resource[IO, HikariTransactor[IO]] =
  HikariTransactor.newHikariTransactor[IO](
    "org.postgresql.Driver",
    "jdbc:postgresql://localhost/app",
    "postgres", "secret",
    connectEC
  )

なぜResourceなのか

プールされたTransactorは、開いた接続やバックグラウンドスレッドなど、長期間存続する状態を所有します。Resource[F, A]は、エラーやキャンセルが発生しても取得と解放が必ず対になることを保証します。

通常は起動時にTransactorを一度構築し、アプリケーションの存続期間全体で再利用します。

xaRes.use { xa =>
  program.transact(xa)
}

connectECプール

HikariCPは、プールから接続を待つためのExecutionContextを必要とします。DoobieはそのためにExecutionContexts.fixedThreadPoolを提供しており、これ自体もResourceです。

これを計算用プールから分離すると、ブロッキングする接続取得によってCPUバウンドの処理が枯渇するのを防げます。

import doobie.util.ExecutionContexts

val poolRes =
  for {
    ec <- ExecutionContexts.fixedThreadPool[IO](8)
    xa <- HikariTransactor.newHikariTransactor[IO](
            "org.postgresql.Driver", url, user, pass, ec)
  } yield xa

既存のDataSourceの設定

設定済みのjavax.sql.DataSource(例:調整済みのHikariインスタンス)がすでにある場合は、Transactor.fromDataSourceで直接ラップします。

フレームワークがプールを管理し、Doobieにはそれを利用させるだけにしたい場合によく使われます。

val xa = Transactor.fromDataSource[IO](
  dataSource = myDataSource,
  connectEC = connectEC
)

接続のスモークテスト

簡単なヘルスチェックとして、Transactor経由でselect 1を実行します。結果が返れば、ドライバー、URL、認証情報がすべて機能しています。

実際のクエリを組み込む前の最初の手順として適しています。

val check: IO[Int] =
  sql"select 1".query[Int].unique.transact(xa)

// check.unsafeRunSync() == 1

Transactorの内部:Strategy

TransactorはインタープリターとStrategyから構築されます。Strategyは各トランザクションの前後で行う処理、つまりbefore、after、oops(エラー時)、alwaysを制御します。

デフォルトのStrategyは、自動コミットを無効にし、成功後にコミットし、エラー時にロールバックし、常に接続を閉じます。

import doobie.util.transactor.Strategy

val noCommit = xa.copy(
  strategy0 = Strategy.default.copy(after = doobie.free.connection.unit)
)

ロギングと可観測性

Doobieでは、すべてのステートメント、その引数、実行時間をログに記録できます。最近のバージョンでは、TransactorごとではなくクエリごとにLogHandler[F]を設定します。

本番環境で遅いクエリを見つけたり、パラメーターのバインドを確認したりするうえで非常に役立ちます。

import doobie.util.log._

val handler: LogHandler[IO] = (ev: LogEvent) =>
  IO.println(ev.sql)

クイックチェック

Transactorについての理解度を確認しましょう。

まとめ

Transactor[F]は、純粋なConnectionIOプログラムを実際のデータベースに接続します。fromDriverManagerはテストに適しており、HikariTransactorとfromDataSourceは接続プールを利用する本番環境に適しています。

プールを使用するTransactorはResourceとして構築し、.transact(xa)でプログラムを実行します。コミット、ロールバック、後片付けはデフォルトのStrategyに任せます。

よくある質問

「Transactorで接続する」レッスンは無料ですか?

はい。「Transactorで接続する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「Transactorで接続する」で何を学びますか?

データベースへのアクセスを設定します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「Transactorで接続する」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Transactorで接続する
  2. クエリを実行する
  3. 挿入と更新
  4. トランザクションを組み合わせる
← Scala for Backend Engineering & Functional Programmingに戻る