Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

E コマースサイトで D1 の読み取りレプリケーションを使う

最終更新 Markdown で表示Agent セットアップ

D1 の読み取りレプリケーション は、D1 データベースを複数リージョンに複製する機能です。E コマースサイトでは、読み取りレイテンシを下げ、読み取りスループットを上げられます。このチュートリアルでは、E コマースサイトで D1 の読み取りレプリケーションを使う方法を学びます。

架空の E コマースサイトを使いますが、原則は、低い読み取りレイテンシと読み取りのスケールが必要な用途に当てはめられます。ニュースサイト、ソーシャルメディア、マーケティングサイトなどです。

クイックスタート

手順を飛ばしてすぐ始める場合は、次のボタンをクリックします。

Deploy to Cloudflare

GitHub アカウントにリポジトリが作成され、アプリケーションが Cloudflare Workers にデプロイされます。D1 データベースの作成とバインド、必要なテーブルの作成、サンプルデータの追加も行われます。デプロイ時に Enable read replication にチェックを入れ、読み取りレプリケーションを有効にします。

デプロイしたアプリケーションにアクセスできます。

前提条件

  1. Cloudflare アカウント に登録します。
  2. Node.js をインストールします。

Node.js のバージョンマネージャー

権限の問題を避け、Node.js のバージョンを切り替えられるよう、Voltanvm などの Node バージョンマネージャーを使います。このガイドの後半で説明する Wrangler には、Node バージョン 16.17.0 以降が必要です。

ステップ 1: Workers プロジェクトを作成する

次のコマンドで、新しい Workers プロジェクトを作成します。

npm create cloudflare@latest -- fast-commerce

セットアップでは、次のオプションを選びます。

  • What would you like to start with? では、Hello World example を選びます。
  • Which template would you like to use? では、SSR / full-stack app を選びます。
  • Which language do you want to use? では、TypeScript を選びます。
  • Do you want to use git for version control? では、Yes を選びます。
  • Do you want to deploy your application? では、No を選びます(デプロイ前にいくつか変更します)。

API ルートには Hono を使います。次のコマンドで Hono をインストールします。

npm i hono

ステップ 2: フロントエンドを更新する

前のステップで、デフォルトのフロントエンドを持つ Workers プロジェクトが作成され、Hono がインストールされます。フロントエンドを更新し、商品一覧を表示します。単一商品を表示するページも追加します。

作成した Worker プロジェクトのフォルダーへ移動します。

cd fast-commerce

public/index.html を更新し、商品一覧を表示します。次のコードを参考にしてください。

public/index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>E-commerce Store</title>
		<style>
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
				font-family: Arial, sans-serif;
			}

    		body {
    			background-color: #f9fafb;
    			min-height: 100vh;
    			display: flex;
    			flex-direction: column;
    		}

    		header {
    			background-color: white;
    			padding: 1rem 2rem;
    			display: flex;
    			justify-content: space-between;
    			align-items: center;
    			border-bottom: 1px solid #e5e7eb;
    		}

    		.store-title {
    			font-weight: bold;
    			font-size: 1.25rem;
    		}

    		.cart-button {
    			padding: 0.5rem 1rem;
    			cursor: pointer;
    			background: none;
    			border: none;
    		}

    		.products-grid {
    			display: grid;
    			grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    			gap: 1.5rem;
    			padding: 2rem;
    		}

    		.product-card {
    			background-color: white;
    			border-radius: 0.5rem;
    			overflow: hidden;
    			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    		}

    		.product-info {
    			padding: 1rem;
    		}

    		.product-title {
    			font-size: 1.125rem;
    			font-weight: 600;
    			margin-bottom: 0.5rem;
    		}

    		.product-description {
    			color: #4b5563;
    			font-size: 0.875rem;
    			margin-bottom: 1rem;
    		}

    		.product-price {
    			font-size: 1.25rem;
    			font-weight: bold;
    			margin-bottom: 0.5rem;
    		}

    		.product-stock {
    			color: #4b5563;
    			font-size: 0.875rem;
    			margin-bottom: 1rem;
    		}

    		.view-details-btn {
    			display: block;
    			width: 100%;
    			padding: 0.5rem 0;
    			background-color: #2563eb;
    			color: white;
    			border: none;
    			border-radius: 0.375rem;
    			cursor: pointer;
    			text-align: center;
    			text-decoration: none;
    			font-size: 0.875rem;
    		}

    		.view-details-btn:hover {
    			background-color: #1d4ed8;
    		}

    		footer {
    			background-color: white;
    			padding: 1rem 2rem;
    			text-align: center;
    			border-top: 1px solid #e5e7eb;
    			color: #4b5563;
    			font-size: 0.875rem;
    		}

    		/* Basic Responsiveness */
    		@media (max-width: 768px) {
    			.products-grid {
    				grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    			}
    		}

    		@media (max-width: 480px) {
    			.products-grid {
    				grid-template-columns: 1fr;
    			}
    		}
    	</style>
    </head>
    <body>
    	<header>
    		<h1 class="store-title">E-commerce Store</h1>
    		<button class="cart-button">Cart</button>
    	</header>

    	<main class="products-grid" id="products-container">
    		<!-- Products will be loaded here by JavaScript -->
    	</main>

    	<footer>
    		<p>© 2025 E-commerce Store. All rights reserved.</p>
    	</footer>

    	<script>
    		document.addEventListener('DOMContentLoaded', () => {
    			let products = [];
    			let d1Duration,
    				queryDuration = 0;
    			let dbLocation;
    			let isPrimary = true;

    			// Function to create product HTML
    			function createProductCard(product) {
    				return `
                <div class="product-card" data-category="${product.category}">
                    <div class="product-info">
                        <h3 class="product-title">${product.name}</h3>
                        <p class="product-description">${product.description}</p>
                        <p class="product-price">$${product.price.toFixed(2)}</p>
                        <p class="product-stock">${product.inventory} in stock</p>
                        <a href="product-details.html?id=${product.id}" class="view-details-btn">View Details</a>
                    </div>
                </div>
            `;
    			}

    			// Function to render content
    			function renderContent() {
    				try {
    					const productsContainer = document.getElementById('products-container');
    					if (!productsContainer) return;
    					productsContainer.innerHTML = '';

    					products.forEach((product) => {
    						productsContainer.innerHTML += createProductCard(product);
    					});
    				} catch (error) {
    					console.error('Error rendering content:', error);
    				}
    			}

    			// Fetch products
    			fetch('/api/products')
    				.then((response) => response.json())
    				.then((data) => {
    					products = data;
    					renderContent();
    				})
    				.catch((error) => console.error('Error fetching products:', error));
    		});
    	</script>
    </body>

</html>

単一商品を表示する public/product-details.html を新規作成します。

public/product-details.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Product Details - E-commerce Store</title>
		<style>
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
				font-family: Arial, sans-serif;
			}

			body {
				background-color: #f9fafb;
				min-height: 100vh;
				display: flex;
				flex-direction: column;
			}

			header {
				background-color: white;
				padding: 1rem 2rem;
				display: flex;
				justify-content: space-between;
				align-items: center;
				border-bottom: 1px solid #e5e7eb;
			}

			.store-title {
				font-weight: bold;
				font-size: 1.25rem;
				text-decoration: none;
				color: black;
			}

			.cart-button {
				padding: 0.5rem 1rem;
				cursor: pointer;
				background: none;
				border: none;
			}

			.product-container {
				max-width: 800px;
				margin: 2rem auto;
				background-color: white;
				border-radius: 0.5rem;
				box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
				padding: 2rem;
			}

			.product-title {
				font-size: 1.875rem;
				font-weight: bold;
				margin-bottom: 0.5rem;
			}

			.product-description {
				color: #4b5563;
				margin-bottom: 1.5rem;
			}

			.product-price {
				font-size: 1.875rem;
				font-weight: bold;
				margin-bottom: 0.5rem;
			}

			.product-stock {
				font-size: 0.875rem;
				color: #4b5563;
				text-align: right;
			}

			.add-to-cart-btn {
				display: block;
				width: 100%;
				padding: 0.75rem;
				background-color: #2563eb;
				color: white;
				border: none;
				border-radius: 0.375rem;
				cursor: pointer;
				text-align: center;
				font-size: 1rem;
				margin-top: 1.5rem;
			}

			.add-to-cart-btn:hover {
				background-color: #1d4ed8;
			}

			.price-stock-container {
				display: flex;
				justify-content: space-between;
				align-items: center;
				margin-bottom: 1rem;
			}

			footer {
				background-color: white;
				padding: 1rem 2rem;
				text-align: center;
				border-top: 1px solid #e5e7eb;
				color: #4b5563;
				font-size: 0.875rem;
				margin-top: auto;
			}

			/* Back button */
			.back-button {
				display: inline-block;
				margin-bottom: 1.5rem;
				color: #2563eb;
				text-decoration: none;
				font-size: 0.875rem;
			}

			.back-button:hover {
				text-decoration: underline;
			}

			/* Notification */
			.notification {
				position: fixed;
				top: 1rem;
				right: 1rem;
				background-color: #10b981;
				color: white;
				padding: 0.75rem 1rem;
				border-radius: 0.375rem;
				box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
				transform: translateX(150%);
				transition: transform 0.3s ease;
			}

			.notification.show {
				transform: translateX(0);
			}
		</style>
	</head>
	<body>
		<header>
			<a href="index.html" class="store-title">E-commerce Store</a>
			<button class="cart-button">Cart</button>
		</header>

		<main class="product-container">
			<a href="index.html" class="back-button">← Back to products</a>
			<h1 class="product-title" id="product-title">Product Name</h1>
			<p class="product-description" id="product-description">
				Product description goes here.
			</p>

			<div class="price-stock-container">
				<p class="product-price" id="product-price">$0.00</p>
				<p class="product-stock" id="product-stock">0 in stock</p>
			</div>

			<button class="add-to-cart-btn" id="add-to-cart">Add to Cart</button>
		</main>

		<div class="notification" id="notification">Added to cart!</div>

		<footer>
			<p>© 2025 E-commerce Store. All rights reserved.</p>
		</footer>

		<script>
			// Get query parameter from URL
			const url = new URL(window.location.href);
			const searchParams = new URLSearchParams(url.search);
			const productId = searchParams.get("id");

			// Fetch product details
			fetch(`/api/products/${productId}`)
				.then((response) => response.json())
				.then((product) => displayContent(product))
				.catch((error) =>
					console.error("Error fetching product details:", error),
				);

			// Function to display product details
			function displayContent(product) {
				document.title = `${product[0].name} - E-commerce Store`;
				document.getElementById("product-title").textContent = product[0].name;
				document.getElementById("product-description").textContent =
					product[0].description;
				document.getElementById("product-price").textContent =
					`$${product[0].price.toFixed(2)}`;
				document.getElementById("product-stock").textContent =
					`${product[0].inventory} in stock`;
			}
		</script>
	</body>
</html>

商品一覧と単一商品を表示するフロントエンドができました。ただし、まだ D1 データベースにはつながっていません。いま開発サーバーを起動しても、商品は表示されません。次のステップで D1 データベースを作成し、商品を取得してフロントエンドに表示する API を作ります。

ステップ 3: D1 データベースを作成し、読み取りレプリケーションを有効にする

次のコマンドで、新しい D1 データベースを作成します。

npx wrangler d1 create fast-commerce

ターミナルに返った D1 バインディングを wrangler ファイルに追加します。

{
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "fast-commerce",
			"database_id": "YOUR_DATABASE_ID"
		}
	]
}
[[d1_databases]]
binding = "DB"
database_name = "fast-commerce"
database_id = "YOUR_DATABASE_ID"

次のコマンドを実行し、worker-configuration.d.tsEnv インターフェイスを更新します。

npm run cf-typegen

次に、D1 データベースで読み取りレプリケーションを有効にします。Workers & Pages > D1 を開き、既存のデータベースを選択して Settings > Enable Read Replication を選びます。

ステップ 4: API ルートを作成する

src/index.ts を更新し、Hono ライブラリをインポートして API ルートを作成します。

import { Hono } from "hono";
// Set db session bookmark in the cookie
import { getCookie, setCookie } from "hono/cookie";

const app = new Hono<{ Bindings: Env }>();

// Get all products
app.get("/api/products", async (c) => {
	return c.json({ message: "get list of products" });
});

// Get a single product
app.get("/api/products/:id", async (c) => {
	return c.json({ message: "get a single product" });
});

// Upsert a product
app.post("/api/product", async (c) => {
	return c.json({ message: "create or update a product" });
});

export default app;

上記のコードは、次の 3 つの API ルートを作成します。

  • GET /api/products: 商品一覧を返します。
  • GET /api/products/:id: 単一商品を返します。
  • POST /api/product: 商品を作成または更新します。

ただし、API ルートはまだ D1 データベースにつながっていません。次のステップで D1 に products テーブルを作成し、API ルートを D1 に接続します。

ステップ 5: ローカル D1 のデータベーススキーマを作成する

次のコマンドで、D1 データベースに products テーブルを作成します。

npx wrangler d1 execute fast-commerce --command "CREATE TABLE IF NOT EXISTS products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT, price DECIMAL(10, 2) NOT NULL, inventory INTEGER NOT NULL DEFAULT 0, category TEXT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)"

次に、次のコマンドで products テーブルにインデックスを作成します。

npx wrangler d1 execute fast-commerce --command "CREATE INDEX IF NOT EXISTS idx_products_id ON products (id)"

開発用に、次のコマンドでローカル D1 データベースへ INSERT 文を実行することもできます。

npx wrangler d1 execute fast-commerce --command "INSERT INTO products (id, name, description, price, inventory, category) VALUES (1, 'Fast Ergonomic Chair', 'A comfortable chair for your home or office', 100.00, 10, 'Furniture'), (2, 'Fast Organic Cotton T-shirt', 'A comfortable t-shirt for your home or office', 20.00, 100, 'Clothing'), (3, 'Fast Wooden Desk', 'A wooden desk for your home or office', 150.00, 5, 'Furniture'), (4, 'Fast Leather Sofa', 'A leather sofa for your home or office', 300.00, 3, 'Furniture'), (5, 'Fast Organic Cotton T-shirt', 'A comfortable t-shirt for your home or office', 20.00, 100, 'Clothing')"

ステップ 6: リトライロジックを追加する

アプリケーションを堅牢にするため、API ルートにリトライロジックを追加できます。src ディレクトリに retry.ts を新規作成します。

export interface RetryConfig {
	maxRetries: number;
	initialDelay: number;
	maxDelay: number;
	backoffFactor: number;
}

const shouldRetry = (error: unknown): boolean => {
	const errMsg = error instanceof Error ? error.message : String(error);
	return (
		errMsg.includes("Network connection lost") ||
		errMsg.includes("storage caused object to be reset") ||
		errMsg.includes("reset because its code was updated")
	);
};

// Helper function for sleeping
const sleep = (ms: number): Promise<void> => {
	return new Promise((resolve) => setTimeout(resolve, ms));
};

export const defaultRetryConfig: RetryConfig = {
	maxRetries: 3,
	initialDelay: 100,
	maxDelay: 1000,
	backoffFactor: 2,
};

export async function withRetry<T>(
	operation: () => Promise<T>,
	config: Partial<RetryConfig> = defaultRetryConfig,
): Promise<T> {
	const maxRetries = config.maxRetries ?? defaultRetryConfig.maxRetries;
	const initialDelay = config.initialDelay ?? defaultRetryConfig.initialDelay;
	const maxDelay = config.maxDelay ?? defaultRetryConfig.maxDelay;
	const backoffFactor =
		config.backoffFactor ?? defaultRetryConfig.backoffFactor;

	let lastError: Error | unknown;
	let delay = initialDelay;

	for (let attempt = 0; attempt <= maxRetries; attempt++) {
		try {
			const result = await operation();
			return result;
		} catch (error) {
			lastError = error;

			if (!shouldRetry(error) || attempt === maxRetries) {
				throw error;
			}

			// Add randomness to avoid synchronizing retries
			// Wait for a random delay between delay and delay*2
			await sleep(delay * (1 + Math.random()));

			// Calculate next delay with exponential backoff
			delay = Math.min(delay * backoffFactor, maxDelay);
		}
	}

	throw lastError;
}

withRetry は、指数バックオフで指定した操作を再試行するユーティリティ関数です。設定オブジェクトを受け取り、リトライ回数、初期遅延、最大遅延、バックオフ係数をカスタマイズできます。再試行するのは、ネットワーク切断、ストレージリセット、コード更新が原因のエラーのときだけです。

次に、src/index.ts を更新し、withRetry 関数をインポートして API ルートで使います。

import { withRetry } from "./retry";

ステップ 7: API ルートを更新する

API ルートを更新し、D1 データベースに接続します。

1. POST /api/product

app.post("/api/product", async (c) => {
	const product = await c.req.json();

	if (!product) {
		return c.json({ message: "No data passed" }, 400);
	}

	const db = c.env.DB;
	const session = db.withSession("first-primary");

	const { id } = product;

	try {
		return await withRetry(async () => {
			// Check if the product exists
			const { results } = await session
				.prepare("SELECT * FROM products where id = ?")
				.bind(id)
				.run();
			if (results.length === 0) {
				const fields = [...Object.keys(product)];
				const values = [...Object.values(product)];
				// Insert the product
				await session
					.prepare(
						`INSERT INTO products (${fields.join(", ")}) VALUES (${fields.map(() => "?").join(", ")})`,
					)
					.bind(...values)
					.run();
				const latestBookmark = session.getBookmark();
				latestBookmark &&
					setCookie(c, "product_bookmark", latestBookmark, {
						maxAge: 60 * 60, // 1 hour
					});
				return c.json({ message: "Product inserted" });
			}

			// Update the product
			const updates = Object.entries(product)
				.filter(([_, value]) => value !== undefined)
				.map(([key, _]) => `${key} = ?`)
				.join(", ");

			if (!updates) {
				throw new Error("No valid fields to update");
			}

			const values = Object.entries(product)
				.filter(([_, value]) => value !== undefined)
				.map(([_, value]) => value);

			await session
				.prepare(`UPDATE products SET ${updates} WHERE id = ?`)
				.bind(...[...values, id])
				.run();
			const latestBookmark = session.getBookmark();
			latestBookmark &&
				setCookie(c, "product_bookmark", latestBookmark, {
					maxAge: 60 * 60, // 1 hour
				});
			return c.json({ message: "Product updated" });
		});
	} catch (e) {
		console.error(e);
		return c.json({ message: "Error upserting product" }, 500);
	}
});

上記のコードでは、次を行います。

  • リクエストボディから商品データを取得します。
  • データベースにその商品があるかを確認します。
    • ある場合は、商品を更新します。
    • ない場合は、商品を挿入します。
  • ブックマークを Cookie に設定します。
  • 最後に応答を返します。

最新データでセッションを始めたいので、first-primary 制約を使います。first-unconstrained を使う場合やブックマークを渡す場合でも、書き込みリクエストは常にプライマリデータベースへルーティングされます。

Cookie に設定したブックマークは、新しいセッションが、指定したブックマークと同等以上に新しいデータベースバージョンを読むことを保証するために使えます。

商品管理に外部プラットフォームを使っている場合は、この API をそのプラットフォームに接続できます。外部で商品が作成または更新されると、D1 データベースの商品詳細も自動で更新されます。

2. GET /api/products

app.get("/api/products", async (c) => {
	const db = c.env.DB;

	// Get bookmark from the cookie
	const bookmark = getCookie(c, "product_bookmark") || "first-unconstrained";

	const session = db.withSession(bookmark);

	try {
		return await withRetry(async () => {
			const { results } = await session.prepare("SELECT * FROM products").run();

			const latestBookmark = session.getBookmark();

			// Set the bookmark in the cookie
			latestBookmark &&
				setCookie(c, "product_bookmark", latestBookmark, {
					maxAge: 60 * 60, // 1 hour
				});

			return c.json(results);
		});
	} catch (e) {
		console.error(e);
		return c.json([]);
	}
});

上記のコードでは、次を行います。

  • Cookie からデータベースセッションのブックマークを取得します。
    • ブックマークが未設定の場合は、first-unconstrained 制約を使います。
  • そのブックマークでデータベースセッションを作成します。
  • データベースからすべての商品を取得し、最新のブックマークを得ます。
  • このブックマークを Cookie に設定します。
  • 最後に結果を返します。

3. GET /api/products/:id

app.get("/api/products/:id", async (c) => {
	const id = c.req.param("id");

	if (!id) {
		return c.json({ message: "Invalid id" }, 400);
	}

	const db = c.env.DB;

	// Get bookmark from the cookie
	const bookmark = getCookie(c, "product_bookmark") || "first-unconstrained";

	const session = db.withSession(bookmark);

	try {
		return await withRetry(async () => {
			const { results } = await session
				.prepare("SELECT * FROM products where id = ?")
				.bind(id)
				.run();

			const latestBookmark = session.getBookmark();

			// Set the bookmark in the cookie
			latestBookmark &&
				setCookie(c, "product_bookmark", latestBookmark, {
					maxAge: 60 * 60, // 1 hour
				});

			console.log(results);

			return c.json(results);
		});
	} catch (e) {
		console.error(e);
		return c.json([]);
	}
});

上記のコードでは、次を行います。

  • リクエストパラメーターから商品 ID を取得します。
  • ブックマークでデータベースセッションを作成します。
  • データベースから商品を取得し、最新のブックマークを得ます。
  • このブックマークを Cookie に設定します。
  • 最後に結果を返します。

ステップ 8: アプリケーションをテストする

API ルートを D1 データベースに接続しました。開発サーバーを起動し、フロントエンドを開いてアプリケーションをテストできます。

npm run dev

http://localhost:8787 を開きます。商品一覧が表示されます。商品をクリックすると、商品詳細を確認できます。

開発サーバーの起動中に、次のコマンドで新しい商品を挿入します。

curl -X POST http://localhost:8787/api/product \
     -H "Content-Type: application/json" \
     -d '{"id": 6, "name": "Fast Computer", "description": "A computer for your home or office", "price": 1000.00, "inventory": 10, "category": "Electronics"}'

http://localhost:8787/product-details?id=6 を開きます。新しい商品が表示されます。

次のコマンドで商品を更新し、もう一度 http://localhost:8787/product-details?id=6 を開きます。更新後の商品が表示されます。

curl -X POST http://localhost:8787/api/product \
     -H "Content-Type: application/json" \
     -d '{"id": 6, "name": "Fast Computer", "description": "A computer for your home or office", "price": 1050.00, "inventory": 10, "category": "Electronics"}'

ステップ 9: アプリケーションをデプロイする

前のステップで使ったデータベースはローカルです。リモートデータベースにも products テーブルを作成する必要があります。次の D1 コマンドを実行し、リモートデータベースに products テーブルを作成します。

npx wrangler d1 execute fast-commerce --remote --command "CREATE TABLE IF NOT EXISTS products (id INTEGER PRIMARY KEY, name TEXT NOT NULL, description TEXT, price DECIMAL(10, 2) NOT NULL, inventory INTEGER NOT NULL DEFAULT 0, category TEXT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)"

次に、次のコマンドで products テーブルにインデックスを作成します。

npx wrangler d1 execute fast-commerce --remote --command "CREATE INDEX IF NOT EXISTS idx_products_id ON products (id)"

任意で、次のコマンドを実行し、商品をリモートデータベースに挿入できます。

npx wrangler d1 execute fast-commerce --remote --command "INSERT INTO products (id, name, description, price, inventory, category) VALUES (1, 'Fast Ergonomic Chair', 'A comfortable chair for your home or office', 100.00, 10, 'Furniture'), (2, 'Fast Organic Cotton T-shirt', 'A comfortable t-shirt for your home or office', 20.00, 100, 'Clothing'), (3, 'Fast Wooden Desk', 'A wooden desk for your home or office', 150.00, 5, 'Furniture'), (4, 'Fast Leather Sofa', 'A leather sofa for your home or office', 300.00, 3, 'Furniture'), (5, 'Fast Organic Cotton T-shirt', 'A comfortable t-shirt for your home or office', 20.00, 100, 'Clothing')"

次のコマンドでアプリケーションをデプロイできます。

npm run deploy

アプリケーションが Workers にデプロイされ、D1 データベースはリモートリージョンへ複製されます。ユーザーがどのリージョンからリクエストしても、データベースが複製されている最寄りのリージョンへリダイレクトされます。

まとめ

このチュートリアルでは、E コマースサイトで D1 の読み取りレプリケーションを使う方法を学びました。D1 データベースを作成し、読み取りレプリケーションを有効にしました。データベース上で商品を作成・更新する API も作成しました。ブックマークを使って、データベースから最新データを取得する方法も学びました。

リモートデータベースに products テーブルを作成し、アプリケーションをデプロイしました。

読み取りが多い既存アプリケーションにも、同じ方法で読み取りレイテンシを下げ、読み取りスループットを上げられます。コンテンツ管理に外部プラットフォームを使っている場合は、そのプラットフォームを D1 データベースに接続し、コンテンツをデータベースへ自動更新できます。

このチュートリアルの完全なコードは GitHub リポジトリ にあります。

役に立ちましたか?