INTEGRITY Dokumentace

Používání replikace pro čtení D1 pro váš e-shop

D1 Read Replication je funkce, která umožňuje replikovat vaši databázi D1 do více regionů. To se hodí pro e-commerce web, protože snižuje latenci čtení a zvyšuje propustnost čtení. V tomto tutoriálu se naučíte, jak replikaci čtení D1 použít pro svůj e-commerce web.

Ačkoli tento tutoriál používá fiktivní e-shop, tyto principy lze uplatnit na jakýkoli případ použití, který vyžaduje nízkou latenci čtení a škálování čtení, například na zpravodajský web, sociální síť nebo marketingový web.

Rychlý start

Pokud chcete kroky přeskočit a rychle začít, klikněte na tlačítko níže:

Deploy to Cloudflare

Tím se ve vašem účtu GitHub vytvoří repozitář a aplikace se nasadí na Cloudflare Workers. Zároveň se vytvoří a přiváže databáze D1, vytvoří se potřebné tabulky a přidají se ukázková data. Během nasazení zaškrtněte Enable read replication políčko, čímž aktivujete replikaci pro čtení.

Poté můžete navštívit nasazenou aplikaci.

Předpoklady

  1. Zaregistrujte si účet Cloudflare.
  2. Nainstalujte Node.js.

Správce verzí Node.js

Použijte správce verzí Node, jako je Volta nebo nvm abyste se vyhnuli problémům s oprávněními a mohli měnit verze Node.js. Wrangler, o kterém se dozvíte dále v této příručce, vyžaduje verzi Node 16.17.0 nebo novější.

Krok 1: Vytvořte projekt Workers

Nový projekt Workers vytvoříte spuštěním následujícího příkazu:

npm create cloudflare@latest -- fast-commerce

Při nastavení vyberte následující možnosti:

K vytvoření tras API použijete Hono. Hono musíte nainstalovat spuštěním následujícího příkazu:

npm i hono

Krok 2: Aktualizujte frontend

Výše uvedený krok vytvoří nový projekt Workers s výchozím frontendem a nainstaluje Hono. Frontend upravíte tak, aby zobrazoval seznam produktů. Také přidáte novou stránku, která zobrazí jeden produkt.

Přejděte do nově vytvořené složky projektu Worker.

cd fast-commerce

Aktualizujte public/index.html soubor pro výpis produktů. Jako vzor použijte kód níže.

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>

Vytvořte nový public/product-details.html soubor pro zobrazení jednoho produktu.

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>

Nyní máte frontend, který zobrazuje seznam produktů i detail jednotlivého produktu. Frontend zatím není propojen s databází D1. Pokud nyní spustíte vývojový server, žádné produkty neuvidíte. V dalších krocích vytvoříte databázi D1 a API pro načítání produktů a jejich zobrazení na frontendu.

Krok 3: Vytvořte databázi D1 a povolte replikaci pro čtení

Novou databázi D1 vytvoříte spuštěním následujícího příkazu:

npx wrangler d1 create fast-commerce

Vazby D1 vrácené v terminálu přidejte do wrangler soubor:

{
	"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"

Spusťte následující příkaz pro aktualizaci Env rozhraní v worker-configuration.d.ts .

npm run cf-typegen

Dále povolte replikaci pro čtení u databáze D1. Přejděte na Workers & Pages > D1, poté vyberte existující databázi > Nastavení > Enable Read Replication.

Krok 4: Vytvořte trasy API

Aktualizujte src/index.ts soubor, naimportujte knihovnu Hono a vytvořte trasy 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;

Výše uvedený kód vytváří tři trasy API:

Trasy API však zatím nejsou propojeny s databází D1. V dalších krocích vytvoříte v databázi D1 tabulku products a upravíte trasy API tak, aby se k databázi D1 připojovaly.

Krok 5: Vytvořte schéma místní databáze D1

Tabulku products v databázi D1 vytvoříte spuštěním následujícího příkazu:

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)"

Dále vytvořte index na tabulce products spuštěním následujícího příkazu:

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

Pro účely vývoje můžete příkazy INSERT spustit také v lokální databázi D1, a to pomocí následujícího příkazu:

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')"

Krok 6: Přidejte logiku opakování

Pro zvýšení odolnosti aplikace můžete do API tras přidat logiku opakování. Vytvořte nový soubor s názvem retry.ts v src adresář.

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 je pomocná funkce, která opakovaně provádí danou operaci s exponenciálně rostoucí prodlevou (exponential backoff). Jako argument přijímá konfigurační objekt, který umožňuje upravit počet opakování, počáteční prodlevu, maximální prodlevu a faktor prodlužování. Operaci opakuje pouze tehdy, když je chyba způsobena výpadkem síťového připojení, resetem úložiště nebo aktualizací kódu.

Dále aktualizujte src/index.ts soubor a naimportujte withRetry funkci a použijte ji v API routách.

import { withRetry } from "./retry";

Krok 7: Aktualizujte trasy API

Aktualizujte API trasy pro připojení k databázi 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);
	}
});

Ve výše uvedeném kódu:

Protože chcete zahájit relaci s nejnovějšími daty, použijete first-primary omezení. I když použijete first-unconstrained omezení nebo předáte bookmark, požadavek na zápis bude vždy směrován do primární databáze.

Bookmark uložený v cookie lze použít k zajištění toho, že nová relace načte verzi databáze, která je minimálně stejně aktuální jako zadaný bookmark.

Pokud pro správu produktů používáte externí platformu, můžete k ní toto API připojit tak, aby se při vytvoření nebo aktualizaci produktu na externí platformě údaje v databázi D1 automaticky aktualizovaly.

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([]);
	}
});

Ve výše uvedeném kódu:

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([]);
	}
});

Ve výše uvedeném kódu:

Krok 8: Otestujte aplikaci

Nyní máte upravené API routy pro připojení k databázi D1. Aplikaci můžete otestovat spuštěním vývojového serveru a přechodem na frontend.

npm run dev

Přejděte na `http://localhost:8787. Měl by se zobrazit seznam produktů. Kliknutím na produkt zobrazíte jeho podrobnosti.

Pro vložení nového produktu použijte následující příkaz (zatímco běží vývojový server):

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"}'

Přejděte na http://localhost:8787/product-details?id=6. Měl by se zobrazit nový produkt.

Aktualizujte produkt pomocí následujícího příkazu a přejděte na http://localhost:8787/product-details?id=6 znovu. Zobrazí se vám aktualizovaný produkt.

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"}'

Krok 9: Nasaďte aplikaci

Databáze, kterou jste použili v předchozích krocích, je místní, proto musíte tabulku products vytvořit i ve vzdálené databázi. Tabulku products ve vzdálené databázi vytvoříte pomocí následujících příkazů D1.

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)"

Dále vytvořte index na tabulce products spuštěním následujícího příkazu:

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

Volitelně můžete produkty vložit do vzdálené databáze spuštěním následujícího příkazu:

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')"

Nyní můžete aplikaci nasadit pomocí následujícího příkazu:

npm run deploy

Tím se aplikace nasadí na Workers a databáze D1 se replikuje do vzdálených regionů. Pokud uživatel požaduje aplikaci z libovolného regionu, požadavek se přesměruje do nejbližšího regionu, kam je databáze replikována.

Závěr

V tomto tutoriálu jste se naučili, jak pro svůj e-commerce web použít D1 Read Replication. Vytvořili jste databázi D1 a zapnuli pro ni replikaci pro čtení. Následně jste vytvořili API pro vytváření a aktualizaci produktů v databázi. Také jste se naučili, jak pomocí bookmarku získat nejnovější data z databáze.

Poté jste ve vzdálené databázi vytvořili tabulku products a nasadili aplikaci.

Stejný postup můžete použít i u stávající aplikace náročné na čtení ke snížení latence čtení a zvýšení propustnosti čtení. Pokud pro správu obsahu používáte externí platformu, můžete ji propojit s databází D1, takže se obsah v databázi bude aktualizovat automaticky.

Kompletní kód pro tento tutoriál najdete v Repozitář GitHub.