コンテンツにスキップ

Prisma@SQLパッケージ

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. Prismaの仕組み

PrismaClient (JavaScriptパッケージ) は、クエリエンジン (バイナリ) に接続リクエストを送信する。

クエリエンジンはコネクションプールを作成し、プール内のコネクションを使用してDBに接続する。

コネクションが維持されている間、これを再利用して複数のクエリを実行する。

PrismaClientは、クエリエンジンに切断リクエストを送信する。

クエリエンジンは、データベースとのコネクションを破棄する。

architecture_prisma


02. セットアップ

アップグレード

@prisma/clientパッケージとprismaパッケージの両方をアップグレードする必要がある。

$ yarn upgrade @prisma/client@<バージョン>

$ yarn upgrade prisma<バージョン>


02. コマンド

generate

Prismaスキーマからクライアントを作成する。

クライアントを使用して、データベースに接続できる。

マイグレーションや初期データを挿入前に必要である。

$ yarn prisma generate

✔ Generated Prisma Client (4.16.2 | library) to ./node_modules/@prisma/client in 177ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client

import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()


migrate

▼ dev

ローカル環境用のマイグレーションを実行する。

$ prisma migrate dev

▼ deploy

本番環境用のマイグレーションを実行する。

$ prisma migrate deploy

▼ reset

初期の状態まで、全てロールバックする。

--forceオプションで警告を無視できる。

$ prisma migrate reset --force


db

▼ seed

ローカル環境用の初期データを挿入する。

$ yarn prisma db seed


03. スキーマ

datasource

▼ datasourceとは

データベース情報を設定する。

▼ url

プロトコル名として、mysqlpostgresqlを設定できる。

datasource db {
  provider = "<プロトコル名>"
  // 例:mysql://user:password@<AWS Auroraクラスターのリーダーエンドポイント>:3306/foo
  url      = "<プロトコル名>://<DBユーザー>:<DBパスワード>@<DBホスト>:<ポート番号>/<DB名>?schema=public&connection_limit=30&pool_timeout=60"
}

注意点として、DBパスワードに特殊記号が含まれている場合、URLエンコードする必要がある。

$ alias urldecode='python3 -c "import sys, urllib.parse as ul; \
    print(ul.unquote_plus(sys.argv[1]))"'

$ urldecode 'q+werty%3D%2F%3B'
q werty=/;
$ alias urlencode='python3 -c "import sys, urllib.parse as ul; \
    print (ul.quote_plus(sys.argv[1]))"'

$ urlencode 'q werty=/;'
q+werty%3D%2F%3B

▼ urlパラメーター

URLのパラメーターとして、以下などを設定できる。

  • コネションプールのコネクション上限数 (connection_limit)
  • コネクションプール内のコネクションが空くまでの待機時間 (pool_timeout)


generator

generator client {
  provider   = "prisma-client-js"
  engineType = "library"
}


04. PrismaClient

$transaction

▼ $transaction

複数のクエリ処理を実行するトランザクションを定義する。

import {PrismaClient} from "@prisma/client";

const prisma = new PrismaClient();

function transfer(from: string, to: string, amount: number) {
  // トランザクション
  return prisma.$transaction(async (tx) => {
    // CRUD処理
    const sender = await tx.account.update({
      data: {
        balance: {
          decrement: amount,
        },
      },
      where: {
        email: from,
      },
    });

    if (sender.balance < 0) {
      throw new Error(`${from} doesn't have enough to send ${amount}`);
    }

    // CRUD処理
    const recipient = await tx.account.update({
      data: {
        balance: {
          increment: amount,
        },
      },
      where: {
        email: to,
      },
    });

    return recipient;
  });
}

async function main() {
  // $transaction関数の実行をtry-catchブロックで囲む
  try {
    await transfer("alice@prisma.io", "bob@prisma.io", 100);
    await transfer("alice@prisma.io", "bob@prisma.io", 100);
  } catch (err) {}
}

main();

▼ オプション

import {PrismaClient} from '@prisma/client'

// トランザクションのオプションはトランザクション全体で統一する
let prismaClientOption = {
  // データを取得するまでのタイムアウト値 (デフォルトは2000ms)
  transactionOptions: {
    // データを取得するまでのタイムアウト値 (デフォルトは2000ms)
    maxWait: 5000,
    // ロールバックを含めて全体が完了するまでのタイムアウト値 (デフォルトは5000ms)
    timeout: 10000,
    // トランザクションの分離レベル
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
  }
}

// Prismaクライアントに設定する
const prisma = new PrismaClient(prismaClientOption)

function transfer(...) {

  return prisma.$transaction(
      async (tx) => {
        // CRUD処理
      })
}

async function main() {

  try {
    await transfer(...)
  } catch (err) {

  }
}

main()
import {PrismaClient} from '@prisma/client'

const prisma = new PrismaClient()

let prismaClientOption = {
  // データを取得するまでのタイムアウト値 (デフォルトは2000ms)
  transactionOptions: {
    // データを取得するまでのタイムアウト値 (デフォルトは2000ms)
    maxWait: 5000,
    // ロールバックを含めて全体が完了するまでのタイムアウト値 (デフォルトは5000ms)
    timeout: 10000,
    // トランザクションの分離レベル
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
  }
}

function transfer(...) {

  return prisma.$transaction(
      async (tx) => {
        // CRUD処理
      },
      // トランザクションに個別に設定する
      prismaClientOption
  )
}

async function main() {

  try {
    await transfer(...)
  } catch (err) {

  }
}

main()