Files
gh-djankies-claude-configs-…/skills/configuring-transaction-isolation/references/complete-examples.md
2025-11-29 18:22:25 +08:00

4.9 KiB

Complete Examples

Example 1: Banking Transfer

Input: Transfer money between accounts with strict consistency.

Implementation:

import { Prisma } from '@prisma/client';

async function transferMoney(
  fromAccountId: string,
  toAccountId: string,
  amount: number
) {
  if (amount <= 0) {
    throw new Error('Amount must be positive');
  }

  try {
    const result = await prisma.$transaction(
      async (tx) => {
        const fromAccount = await tx.account.findUnique({
          where: { id: fromAccountId }
        });

        if (!fromAccount) {
          throw new Error('Source account not found');
        }

        if (fromAccount.balance < amount) {
          throw new Error('Insufficient funds');
        }

        const toAccount = await tx.account.findUnique({
          where: { id: toAccountId }
        });

        if (!toAccount) {
          throw new Error('Destination account not found');
        }

        await tx.account.update({
          where: { id: fromAccountId },
          data: { balance: { decrement: amount } }
        });

        await tx.account.update({
          where: { id: toAccountId },
          data: { balance: { increment: amount } }
        });

        const transfer = await tx.transfer.create({
          data: {
            fromAccountId,
            toAccountId,
            amount,
            status: 'COMPLETED',
            completedAt: new Date()
          }
        });

        return transfer;
      },
      {
        isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
        maxWait: 5000,
        timeout: 10000
      }
    );

    return { success: true, transfer: result };

  } catch (error) {
    if (error.code === 'P2034') {
      throw new Error('Transaction conflict - please retry');
    }
    throw error;
  }
}

Example 2: Inventory Reservation

Input: Reserve inventory items for an order.

Implementation:

async function reserveInventory(
  orderId: string,
  items: Array<{ productId: string; quantity: number }>
) {
  const maxRetries = 3;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      await prisma.$transaction(
        async (tx) => {
          for (const item of items) {
            const product = await tx.product.findUnique({
              where: { id: item.productId }
            });

            if (!product) {
              throw new Error(`Product ${item.productId} not found`);
            }

            if (product.stock < item.quantity) {
              throw new Error(
                `Insufficient stock for ${product.name}`
              );
            }

            await tx.product.update({
              where: { id: item.productId },
              data: { stock: { decrement: item.quantity } }
            });

            await tx.reservation.create({
              data: {
                orderId,
                productId: item.productId,
                quantity: item.quantity,
                reservedAt: new Date()
              }
            });
          }
        },
        {
          isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
          maxWait: 3000,
          timeout: 8000
        }
      );

      return { success: true };

    } catch (error) {
      if (error.code === 'P2034' && attempt < maxRetries - 1) {
        await new Promise(resolve =>
          setTimeout(resolve, Math.pow(2, attempt) * 200)
        );
        continue;
      }

      throw error;
    }
  }

  throw new Error('Reservation failed after retries');
}

Example 3: Seat Booking with Status Check

Input: Book a seat with concurrent user protection.

Implementation:

async function bookSeat(
  userId: string,
  eventId: string,
  seatNumber: string
) {
  try {
    const booking = await prisma.$transaction(
      async (tx) => {
        const seat = await tx.seat.findFirst({
          where: {
            eventId,
            seatNumber
          }
        });

        if (!seat) {
          throw new Error('Seat not found');
        }

        if (seat.status !== 'AVAILABLE') {
          throw new Error('Seat is no longer available');
        }

        await tx.seat.update({
          where: { id: seat.id },
          data: {
            status: 'BOOKED',
            bookedAt: new Date()
          }
        });

        const booking = await tx.booking.create({
          data: {
            userId,
            seatId: seat.id,
            eventId,
            status: 'CONFIRMED',
            bookedAt: new Date()
          }
        });

        return booking;
      },
      {
        isolationLevel: Prisma.TransactionIsolationLevel.Serializable
      }
    );

    return { success: true, booking };

  } catch (error) {
    if (error.code === 'P2034') {
      throw new Error(
        'Seat was just booked by another user - please select another seat'
      );
    }
    throw error;
  }
}