MongoDB Academy · Lektion

Starta en session och en transaktion med flera dokument

Ni öppnar en ClientSession, kör flera operationer i startTransaction() och genomför eller avbryter transaktionen.

Lektion 2 av 413 steg

Starta en session och en transaktion med flera dokument är en gratis lektion i MongoDB Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för MongoDB Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Sessioner är grunden

MongoDB:s transaktioner för flera dokument kräver en session. En session är ett serverbaserat sammanhang som spårar dina kausalt konsekventa läsningar och transaktionens tillstånd. Du skapar en session från MongoClient, skickar den till varje operation i transaktionen och avslutar sedan sessionen när du är klar. Om du glömmer att skicka med sessionsobjektet körs operationerna utanför transaktionen och återställs inte vid avbrytning.

Skapa en session med startSession()

Anropa client.startSession() för att hämta ett ClientSession-objekt. Detta startar inte en transaktion ännu – det etablerar endast det serverbaserade sammanhanget. Sessioner kan valfritt konfigureras för kausal konsistens, så att läsningar i sessionen alltid återspeglar alla tidigare skrivningar i samma session, även på sekundärnoder. Avsluta alltid sessionen i ett finally-block för att frigöra serverresurser.

const { MongoClient } = require('mongodb');
const client = new MongoClient(process.env.MONGODB_URI);

async function run() {
  const session = client.startSession();
  try {
    // ... use session here
  } finally {
    await session.endSession();
    await client.close();
  }
}

Starta en transaktion

Anropa session.startTransaction() med valfria transaktionsalternativ för att starta en transaktion för flera dokument. Vanliga alternativ är readConcern (vanligtvis 'snapshot' för fullständig isolering) och writeConcern (vanligtvis { w: 'majority' } för beständiga commits). När transaktionen har startats ingår alla operationer som skickar med denna session i transaktionen, och de återställs om transaktionen avbryts.

session.startTransaction({
  readConcern: { level: 'snapshot' },
  writeConcern: { w: 'majority' }
});

Skicka sessionen till operationerna

Varje operation som du vill inkludera i transaktionen måste få session-objektet som ett alternativ. Om du glömmer att skicka sessionen till en operation körs den utanför transaktionen med en egen, oberoende skrivning som inte återställs vid avbrytning. Detta är en vanlig felkälla i transaktionskod – kontrollera alltid noggrant att varje insert-, update- och delete-operation i try-blocket får sessionen.

const db = client.db('bank');
const accounts = db.collection('accounts');

// Both operations must receive { session } to be part of the transaction
await accounts.updateOne(
  { _id: fromAccountId },
  { $inc: { balance: -transferAmount } },
  { session }  // <-- REQUIRED
);

await accounts.updateOne(
  { _id: toAccountId },
  { $inc: { balance: transferAmount } },
  { session }  // <-- REQUIRED
);

Commit med commitTransaction()

När alla operationer har slutförts utan fel anropar du session.commitTransaction() för att atomärt tillämpa alla ändringar i databasen. Fram till dess att commit anropas är ingen av transaktionens skrivningar synlig för andra operationer. Vid commit tillämpar MongoDB alla skrivningar och bekräftar dem enligt write concern. En lyckad commit innebär att alla operationer i transaktionen har sparats beständigt.

session.startTransaction();
try {
  await accounts.updateOne({ _id: fromId }, { $inc: { balance: -100 } }, { session });
  await accounts.updateOne({ _id: toId }, { $inc: { balance: 100 } }, { session });
  await session.commitTransaction();
  console.log('Transfer committed successfully');
} catch (error) {
  await session.abortTransaction();
  throw error;
}

Avbryt med abortTransaction()

Om någon operation i transaktionen misslyckas eller om applikationslogiken avgör att transaktionen inte bör fortsätta, anropar du session.abortTransaction(). Detta återställer alla skrivningar som gjorts i transaktionen, som om ingen av dem hade ägt rum. MongoDB garanterar att inget partiellt tillstånd lämnas kvar – andra läsare ser aldrig några av de skrivningar som gjordes i den avbrutna transaktionen.

session.startTransaction();
try {
  const inventory = await db.collection('inventory').findOne({ _id: itemId }, { session });
  
  if (inventory.stock < requestedQty) {
    // Business logic: not enough stock — abort
    await session.abortTransaction();
    return { success: false, reason: 'Insufficient stock' };
  }
  
  await db.collection('inventory').updateOne(
    { _id: itemId }, { $inc: { stock: -requestedQty } }, { session }
  );
  await db.collection('orders').insertOne({ itemId, qty: requestedQty, status: 'confirmed' }, { session });
  await session.commitTransaction();
  return { success: true };
} catch (error) {
  await session.abortTransaction();
  throw error;
}

Hjälpfunktionen withTransaction()

Node.js-drivrutinen tillhandahåller en praktisk hjälpfunktion, session.withTransaction(fn), som automatiskt hanterar att starta, genomföra och avbryta transaktionen, inklusive automatiska omförsök vid övergående fel. Callback-funktionen tar emot sessionen och bör innehålla alla transaktionsåtgärder. Det rekommenderas att använda withTransaction i stället för att manuellt starta, genomföra och avbryta transaktionen, eftersom funktionen hanterar den omförsökslogik som MongoDB kräver på ett korrekt sätt.

const session = client.startSession();
try {
  await session.withTransaction(async () => {
    await accounts.updateOne({ _id: fromId }, { $inc: { balance: -100 } }, { session });
    await accounts.updateOne({ _id: toId }, { $inc: { balance: 100 } }, { session });
    // withTransaction auto-commits on success, auto-aborts on error, and retries transient errors
  }, {
    readConcern: { level: 'snapshot' },
    writeConcern: { w: 'majority' }
  });
} finally {
  await session.endSession();
}

Transaktioners omfattning och samlingar

En MongoDB-transaktion kan omfatta flera samlingar och databaser i samma kluster (MongoDB 4.2+ för shardade kluster). Du kan läsa från en samling, uppdatera en annan och infoga i en tredje – allt inom en enda atomisk transaktion. Den enda begränsningen är att du inte kan skapa nya samlingar eller index i en transaktion som omfattar flera dokument; sådana DDL-åtgärder måste utföras utanför transaktioner.

await session.withTransaction(async () => {
  const db = client.db('ecommerce');
  
  // Span multiple collections in one transaction
  await db.collection('inventory').updateOne(
    { productId: 'P1' }, { $inc: { stock: -qty } }, { session }
  );
  await db.collection('orders').insertOne(
    { productId: 'P1', qty, status: 'new', createdAt: new Date() }, { session }
  );
  await db.collection('customers').updateOne(
    { _id: customerId }, { $push: { orderHistory: orderId } }, { session }
  );
});

Transaktioner kräver replikuppsättningar

Transaktioner som omfattar flera dokument kräver en replikuppsättning eller ett shardat kluster – de fungerar inte på en fristående MongoDB-instans. På en fristående instans finns transaktions-API:t, men ett anrop till startTransaction() utlöser ett fel. Det innebär att din lokala utvecklingsmiljö bör använda en lokal replikuppsättning (till exempel via mongod --replSet rs0 eller Atlas kostnadsfria nivå) om applikationskoden använder transaktioner.

// Starting a local replica set for development:
// 1. Start mongod with replica set name
// mongod --replSet rs0 --port 27017 --dbpath /data/db

// 2. In mongosh, initiate the replica set:
// rs.initiate()

// Now transactions will work on localhost

Tidsgränser och begränsningar för transaktioner

MongoDB tillämpar som standard en maximal livslängd för transaktioner på 60 sekunder (konfigurerbar via transactionLifetimeLimitSeconds). Transaktioner som körs längre avbryts automatiskt. Dessutom är transaktioner begränsade till 16 MB i oplog-utrymme för skrivåtgärder. Långvariga transaktioner håller också lås och kan försämra prestandan för samtidiga åtgärder, så håll transaktionerna korta och fokuserade.

Fullständigt överföringsexempel med validering

Här sätts allt ihop: en komplett, produktionsklar funktion för banköverföringar som använder withTransaction. Funktionen validerar att saldot är tillräckligt i transaktionen (så att ingen annan skrivande process kan ha tömt kontot mellan kontrollen och debiteringen) och registrerar en granskningspost atomiskt. Det här mönstret demonstrerar alla centrala transaktionskoncept.

async function transferFunds(client, fromId, toId, amount) {
  const session = client.startSession();
  try {
    await session.withTransaction(async () => {
      const accounts = client.db('bank').collection('accounts');
      const from = await accounts.findOne({ _id: fromId }, { session });
      
      if (!from || from.balance < amount) {
        throw new Error('Insufficient funds');
      }
      
      await accounts.updateOne({ _id: fromId }, { $inc: { balance: -amount } }, { session });
      await accounts.updateOne({ _id: toId }, { $inc: { balance: amount } }, { session });
      await client.db('bank').collection('auditLog').insertOne(
        { from: fromId, to: toId, amount, date: new Date(), type: 'transfer' }, { session }
      );
    });
    return { success: true };
  } finally {
    await session.endSession();
  }
}

Snabb kontroll

Testa dina kunskaper om MongoDB- och NoSQL-databaser från den här lektionen.

Sammanfattning av lektionen

I den här lektionen har du lärt dig att: transaktioner kräver en ClientSession som skapats med client.startSession(), varje åtgärd i transaktionen måste ta emot { session } för att inkluderas och withTransaction() är den rekommenderade hjälpfunktionen eftersom den automatiskt hanterar omförsökslogik och rensning. Härnäst utforskar vi felhantering och omförsökslogik för övergående transaktionsfel.

Gratis att börja

Lär dig JavaScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”Starta en session och en transaktion med flera dokument” gratis?

Ja – hela texten till ”Starta en session och en transaktion med flera dokument” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i MongoDB Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Starta en session och en transaktion med flera dokument”?

Ni öppnar en ClientSession, kör flera operationer i startTransaction() och genomför eller avbryter transaktionen. Ni övar på MongoDB Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig MongoDB Academy?

Du behöver inga förkunskaper. Utbildningen i MongoDB Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Starta en session och en transaktion med flera dokument”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här MongoDB Academy-lektionen?

Ja. Varje MongoDB Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. ACID-garantier i ett distribuerat dokumentlager
  2. Starta en session och en transaktion med flera dokument
  3. Felhantering och logik för nya försök
  4. Prestandaöverväganden för transaktioner
← Tillbaka till MongoDB Academy