https://a.storyblok.com/f/270183/1368x665/9c72c5f61f/25jun_dev-blog_sqlite.jpg

SQLiteの復活

最終更新日 June 12, 2025

所要時間:3 分

はじめに

OK、認めよう。復帰ではない。むしろ再構築と呼ぼう。 SQLiteはは2000年から存在し、当初の用途はアメリカ海軍駆逐艦のミサイル追跡用だった。過去10年間、NoSQLやドキュメント指向のデータベース・システムが台頭し、SQLiteから脚光を浴びることはなかったが、リレーショナル・データベース・システムとしての信頼性は確かに証明されている。この記事では、SQLiteの見過ごされてきた可能性を探り、本番レベルのアーキテクチャを念頭に置いて、SQLiteがいかに素早くスピンアップできるかを実証する。OK、それは認めよう。むしろ再構築と呼ぼう。SQLiteは2000年から存在している。過去10年間、NoSQLやドキュメント指向のデータベースが台頭し、多くのスポットライトを浴びてきたが、SQLiteは依然として強力な選択肢である。もともとはアメリカ海軍の駆逐艦のミサイル追跡用に開発されたSQLiteは、信頼性の高いリレーショナル・データベースであることを静かに証明してきた。もしかしたら、プロダクション・グレードのアーキテクチャにおけるSQLiteの可能性を見落としているかもしれない。この記事では、SQLiteをいかに速く簡単に立ち上げることができるかを紹介する。

>> TL;DR:完全なソースコードは GitHub.

SQLiteは本番で使えるか?

では、ソフトウェアエンジニア、特にウェブアプリケーション開発者は、SQliteをどのようなものとして知っているのでしょうか?さて、SQliteには2つの評判があります:

  • テストを実行する必要があるのですが、完全な Postgresサーバーを立ち上げたくないので、この便利なファイルを使ってテストを実行するのはどうでしょう?

  • 小さいから組み込み用でしょ?でも、山のようなデータを生成するウェブ・アプリケーションには使えない。

SQLiteはテストに非常に便利だ。例えば、マイグレーションやシーダーなど、既存のアーキテクチャーがコード化されているとします。テスト・スイートを実行するときに、SQL互換のデータベース・サーバー、たとえば MySQL, MariaDBやPostgresのようなSQL互換のデータベースサーバーを使う代わりに、空白のSQLiteファイルを使って同じコードを実行する。素晴らしい。しかし、ポイント2はどうだろう?

SQLiteの優位性:移植性

Dark brown vintage leather briefcase with metal buckles, resting on a round wooden stool against a white backgroundJust one file: portability at its finestそう、小さいのだ。さらに良いのは、接続がシンプルなことだ。

JetbrainsのIDEには、新しいSQLiteファイルを作成できるデータベースパネルがある。 VSCodeにもSQLiteファイルを作成するプラグインがたくさんある。つまり 本当のヘビー 開発者なら Vimから直接作成できる。

フットプリントはわずか699kb。それだけだ。実行するサービスもバックグラウンド・プロセスもない。

これは、完全に MySQL サーバをスピンアップするのに必要なリソースとは大きく異なります。

こんなに簡単なら、なぜもっと多くのウェブ・アプリケーションでSQLiteを使わないのか?

その答えはたいてい思い込みに行き着く。サーバーベースのリレーショナル・データベースが主流だが、少し考えれば、SQLiteが実際の要件に完璧にフィットすることに気づくかもしれない。

SQLiteの優位性:パフォーマンス

読み込みと書き込みの速度は、最大の違いのひとつだ。SQLiteは、数百万行の中規模データベースとしては、信じられないほど高速だ。 信じられないほど速い。 ベンチマークによって異なりますが、MySQLの平均が最大10ms程度であるのに対し、SQLiteは一回のクエリーで最大5msかかります。

しかし、もしSQLiteがすべてのベンチマークで勝っているとしたら、ウェブ・アプリケーションの開発ではそれほど普及していないSQLiteを、私たちが何にでも使っているのは明らかだ。まず、書き込み速度は かなり 遅い。SQLiteはシングルスレッドで約300件のインサートを書き込めるのに対し、MySQLは最大5万件(環境による)。これは大きな違いだ。

2つ目の注意点は、SQLiteにはシングルスレッドのロック機構があるということです。読み取り中または書き込み/更新中のレコードには、5つの書き込み可能な状態があります。書き込み時、レコードのロック状態は EXCLUSIVE,に変更される。しかし、MySQLはMVCC(Multi-Version Concurrency Control)を使用しており、多くの同時読み取りと書き込みが可能である。

使用例

私が常に人々に思い出させようとしている質問のひとつは、次のようなものだ。 あなたのユースケースは何ですか? クラウドネイティブやKubernetesの世界では、「PHPが遅い」のは「Nodeにはイベントループがあるからだ」と主張する人が多い。 現実的にするのか」ということだ。 ユーザーデータを保存したり、CSVや画像をアップロードしたりするのであれば、それは本当に必要なことなのか? 本当に 言語やフレームワークの選択による違いが本当にわかるのでしょうか?多くの場合、おそらくそうではないだろう。これはSQLiteとMySQLでも同じだ:SQLiteは今でも素晴らしい選択肢です。 いくつかの しかしもっと重要なのは、あなたのアプリで2万人のユーザーがデータベースに書き込むつもりなのか、ということだ。グローバル・タクシー・アプリケーションの次のイテレーションを書くのであれば、そうだろう。私がここで言いたいのは、SQLiteは多くの人が思っているよりもはるかに多くの開発ケースに適しているということだ。

プロジェクトの設定

前提条件

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

話はもう十分なので、本番レベルの SQLite を タイプスクリプト.によって生成された Webhook を読むことができるアプリケーションを公開します。 Vonage Messages API によって生成された Webhook を読むことができるアプリケーションを公開します。.まず、プロジェクト用に新しいディレクトリを作成し、そこに移動して、新しい Node プロジェクトを作成します。

npm init --yes

これは package.jsonのデフォルト値が使われる。次に、TypeScriptをインストールする必要がある:

npm install typescript
npx tsc --init

TypescriptはプレーンなJavaScriptにコンパイルされ、設定ファイル tsconfig.json,を使用します。この設定ファイルを開き、定型文を以下のように置き換えてください:

{
 "compilerOptions": {
   "target": "es2016",
   "module": "CommonJS",
   "rootDir": "./",
   "outDir": "./dist",
   "esModuleInterop": true,
   "forceConsistentCasingInFileNames": true,
   "strict": true,
   "skipLibCheck": true,
   "moduleResolution": "node",
   "baseUrl": ".",
   "paths": {
     "@prisma/client":["node_modules/@prisma/client"]
   }
 },
 "include": ["src/**/*.ts"]
}

この構成で注目すべき重要な部分は以下の通りだ:

  • TypeScriptは、存在しなければ作成されるディレクトリにコンパイルされます。 dist.これがアプリケーションのエントリポイントとなる。

  • お気づきのように プリズマpathsキーにあることに気づくだろう。これは、Prismaをインストールする際に、(ある意味で)コンパイルする必要があるからです。Prismaでモデルを定義すると、generateコマンドを使用して特注のPrismaクライアントが作成されます。

私たちには6つの依存関係がある:

これらをコマンドラインで一発インストールできる:

npm install prisma ts-node nodemon dotenv express @types/express sqlite3

プリズマは ORMです。で、データモデル、マイグレーション、その他すべてのクエリを処理できます。Prismaディレクトリをセットアップするには、そのためのinitコマンドを実行する必要があります:

npx prisma init --datasource-provider sqlite --output ../generated/prisma

このコマンドは、コンパイルされたClientクラスを ../generated/prismaディレクトリに出力し、SQLiteがデータベース・ソースであることを指示します。このコマンドを実行すると、Prismaは必要な依存関係を尋ねてきます。 .envファイルを設定します。このファイルは後で設定します。

WebStormでデータベースをセットアップする

SQLiteはライブラリで扱われるファイルなので、ドライバをサポートしている最近のIDEのほとんどで作成できる。あなたのプロジェクトを でプロジェクトを開く。.右側のパネルにある Database アイコンをクリックします。をクリックし、新規データベースを作成します。Data Source "を選択し、"SQLite "が表示されるまで下にスクロールします。新しいデータベースを作成するためのモーダルが表示されます:

Screenshot of generating a new database connection in WebstormJetbrains Supports A Massive List of DBsタイプとしてSQLiteを選択すると、作成ポップアップが表示されます:

Screenshot of SQlite database creation in WebstormCreate Your DatabaseWebStormを使用したことがない場合、初めてこの操作を行うと、IDEはSQliteドライバがインストールされていないことを検知します。 Test Connectionオプションの代わりに警告が表示されます。ドライバを持っていない場合は、リンクをクリックしてインストールしてください。

フィールドで Nameフィールドで identifier.sqliteウェブフックに、ファイル名を webhooks.sqlite.ファイルはプロジェクト・ルートに置きたいので、ファイル・フィールドの右にあるドットを押して、場所が正しいことを確認してください。そしてokをクリックする。

Prismaクライアントは prisma/schema.prismaで設定されていますが DATABASE_URLファイルから .envファイルから取得します。あなたの envを開き、次のように置き換えます:

DATABASE_URL="file:../webhooks.sqlite"

Prismaは、特注のORMクライアントを node_modulesディレクトリに生成するように設定されています。ディレクトリに生成されるように設定されています。 @prismaディレクトリに生成させたくないので schema.prismaファイルで、データソースの下のクライアント設定を次のように置き換えます:

generator client {
 provider = "prisma-client-js"
 output   = "../node_modules/.prisma/client"
}

これは、生成されたクライアントを新しいディレクトリに置くようにPrismaに指示するものです、 .prisma.後でExpressでレコードを作成するときに、Prismaにクライアントをインポートする場所を指示します。

データベースモデルの作成

マイグレーションが実行されるモデルを作成する必要がある。Prismaでは、データベース・モデルをすべて手作業で入力する必要があります。さて、私たちは Vonage Messages API ウェブフックのWebhookリファレンスに移動したらどうだろう? OpenAPI specをコピーして、AIにモデルを書いてもらったらどうだろう?私がやったのはまさにそれだ。

Screenshot of ChatGPT responding to my request to generate a model from the OpenAPI SpecAuto-generated AI code from OpenAPI specs手間を省くために、以下のモデルをあなたの schema.prisma below にコピーしてください:

model WebhookEvent {
 id            String   @id @default(uuid())
 channel       String
 messageUuid   String   @unique
 to            String
 from          String
 timestamp     DateTime
 contextStatus String
 messageType   String
 location      Location?
 createdAt     DateTime @default(now())
}

model Location {
 id        String  @id @default(uuid())
 webhookId String  @unique
 lat       Float
 long      Float
 webhook   WebhookEvent @relation(fields: [webhookId], references: [id], onDelete: Cascade)
}

これでマイグレーションを実行すれば、これらのモデルのテーブルがデータベースに生成されます。

npx prisma migrate dev --name webhooks

Prismaは、データベースに加えられたすべての変更の記録となるマイグレーションを作成しました。フィールド名を変更したいですか?はい、新しいマイグレーションをソースコードにコミットします。これであなたは、アプリケーションのデータベースを正しい状態にする方法の全記録を、コードで持つことができる。

Webhookを扱うExpressアプリケーションの作成

最後のタスクは、Webhookを利用するExpressアプリを作成することです。プロジェクトルートに srcという名前の新しいディレクトリを作成し index.ts.以下のようになります:

import express, { Express, Request, Response } from "express";
import dotenv from 'dotenv';
import { PrismaClient } from ".prisma/client"

dotenv.config();

const app: Express = express();
const port = process.env.PORT;
const prisma = new PrismaClient();

app.use(express.json())

app.get('/', (req: Request, res: Response) => {
 res.send('Express + TypeScript Server');
});

app.post('/webhook', async (req, res) => {
 try {
   const { channel, message_uuid, to, from, timestamp, context_status, message_type, location } = req.body
   // Save the webhook data in the database
   const webhook = await prisma.webhookEvent.create({
     data: {
       channel,
       messageUuid: message_uuid,
       to,
       from,
       timestamp: new Date(timestamp),
       contextStatus: context_status,
       messageType: message_type,
       location: location ? {
         create: {
           lat: location.lat,
           long: location.long
         }
       } : undefined
     },
     include: { location: true } // Optional: Include related location in the response
   })

   console.log('Webhook saved:', webhook)
   res.status(201).json({ message: 'Webhook saved successfully', webhook })
 } catch (error) {
   console.error('Error saving webhook:', error)
   res.status(500).json({ error: 'Internal server error' })
 }
})

app.listen(port, () => {
 console.log(`[server]: Server is running at http://localhost:${port}`);
});

ここで解き明かすことはかなり多いので、一行ずつ見ていこう:

  • import { PrismaClient } from ".prisma/client" .prismaディレクトリからインポートしていることを確認してください。

  • app.use(express.json()) は、ExpressがJSONを処理する必要があることを確認することである。

  • app.post('/webook')は、Vonageがデータを送信する新しいエンドポイントを定義します。 POSTエンドポイントを定義します。

  • ウェブフック・クロージャーで定義された constWebhookクロージャで定義されたフィールドは、必要なフィールドをすべて不変変数に抽出し、データベースに書き込まれます。

  • 最後に prisma.webhookEvent.create()が呼び出され、入力されたデータがSQLiteデータベースに書き込まれる。

コマンドラインからPrismaクライアントを再構築する機能と、TypeScriptでコンパイルするために追加したオプションが必要です。あなたの scriptsセクションの package.jsonファイルのセクションを次のように変更します:

"scripts": {
 "test": "echo \"Error: no test specified\" && exit 1",
 "build": "npm run prisma:generate && npx tsc",
 "start": "node dist/src/index.js",
 "dev": "nodemon --exec ts-node src/index.ts",
 "prisma:generate": "prisma generate"
}

ここでアプリケーションを実行するには、まずアプリを distディレクトリにビルドし、Prismaを再生成してTypeScriptコンパイラーを呼び出した後で、Expressアプリを起動します。

npm run buildnpm run start

お気づきかもしれないが、TypeScriptコンパイラを実行するコマンド npm run devTypeScriptコンパイラーを実行するコマンドと nodemonファイルが変更されるたびにdevビルドを行う

最後の部分は、データを送信することだ。そのためにはまず、ngrokを使ってローカル・アプリケーションをインターネットに公開する必要がある。そのためには、ターミナルで新しいタブを開いて実行する:

ngrok http 3000

学ぶ ngrokの詳細.

ngrokがポートをオープンしたら、パブリックURLができるはずです。これをVonageに設定する。

  • アプリケーションを作成するには アプリケーションの作成ページでアプリケーションの名前を定義します。

  • Webhooksを使用するAPIを使用する場合は、秘密鍵が必要です。Generate public and private key "をクリックすると、自動的にダウンロードが始まります。この鍵は紛失すると再ダウンロードできません。この鍵は紛失しても再ダウンロードできません。 private_<あなたのアプリID>.key.この鍵はAPIコールの認証に使用できます。 注意:アプリケーションを保存するまで、キーは機能しません。

  • 必要な機能(Voice、Messages、RTCなど)を選択し、必要なWebhook(イベントURL、応答URL、受信メッセージURLなど)を提供します。これらはチュートリアルで説明します。

  • 保存してデプロイするには、"Generate new application "をクリックして設定を確定します。これでアプリケーションはVonage APIで使用する準備が整いました。

公開鍵や秘密鍵、その他のオプションは、完全な統合を行うわけではなく、いくつかのデータを生成するだけなので、ここではあまり重要ではない。何が 重要なのは 重要なのは、Ngrokが生成したURLをこれらのインバウンドオプションの両方に貼り付けることです。 /webhookこれはExpressで作成されたルートです。先に進んでアプリケーションを作成し、メッセージ機能はこのようになるはずです:

Screenshot of the Vonage Application dashboard configuration panel showing the webhook endpointsConfiguring your Vonage Application Webhooksこのアプリケーションに添付された番号へのすべての返信は、現在経由で転送されます。インバウンドURLとしてここに入力したURLへのWebhook。

バーチャル電話番号を購入するには APIダッシュボードにアクセスし、以下の手順に従ってください。

Steps on how to purchase a phone number from the dashboard, from selecting the number and confirming the selection.Purchase a phone number

  1. あなたの APIダッシュボード

  2. BUILD & MANAGE > Numbers > Buy Numbersを開きます。

  3. 必要な属性を選択し、検索をクリックします。

  4. ご希望の番号の横にある購入ボタンをクリックし、購入を確定する。

  5. バーチャルナンバーを購入したことを確認するには、左側のナビゲーションメニューの「BUILD & MANAGE」から「Numbers」、「Your Numbers」の順にクリックします。

購入した番号にメッセージを送ると、すべての配線が行われ、イベントと受信メッセージが新しいSQLiteデータベースに直接書き込まれる。ここでは、私のお気に入りのツールを使っている、 HTTPieを使ってウェブフックの送信をテストしてみた:

Screenshot of HTTPie window showing a successful HTTP 201 request to create the recordSuccessful Persistence WinsPHPStormのデータベースパネルからwebhooksテーブルを開くと、レコードが正しく永続化されていることが確認できます:

Database Query View in WebStorm

結論

このデモはSQLiteのパワーを示している。 このコードで このコードで入力されたデータを永続化するために、私たちは何もしていない。Dockerも、リレーショナル・システムのクラウド・スピンアップも使っていない。この紹介は、SQLiteが便利になる可能性のある場所へのポインターの役割を果たす。ローテーションのログファイルや、機械が生成したデータではなく人間が生成したデータの少量バッチ、セッションデータなどだ。同時実行やトラフィックがそれほど気にならない場合は、Redisのような高速なセットアップが可能だと考えてください。しかし、すべてのことに言えることだが、エンジニアのモットーである「It Depends®」を忘れないでほしい。

ご質問がある場合、またはあなたが作っているものを共有したい場合は、こちらをクリックしてください。

最新の開発者向けニュース、ヒント、イベント情報をお届けします。

シェア:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondeシニアPHPデベロッパー

スタンダップ・コメディーの学位論文を持つ俳優の訓練を受け、ミートアップ・シーンを経てPHP開発に携わるようになった。技術について話したり書いたり、レコード・コレクションから変わったレコードを再生したり買ったりしています。