MongoDB Academy · Oppitunti

Istunnon ja usean dokumentin tapahtuman aloittaminen

Oppijat avaavat ClientSession-istunnon, suorittavat useita toimintoja startTransaction()-funktion sisällä ja vahvistavat tai keskeyttävät tapahtuman.

Oppitunti 2/413 vaihetta

Istunnon ja usean dokumentin tapahtuman aloittaminen on ilmainen MongoDB Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu MongoDB Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.

Istunnot ovat perusta

MongoDB:n usean dokumentin transaktiot edellyttävät istuntoa. Istunto on palvelimen puolella ylläpidettävä konteksti, joka seuraa kausaalisesti yhdenmukaisia lukuja ja transaktion tilaa. Luotte istunnon MongoClient-oliosta, välitätte sen jokaiselle transaktion sisäiselle operaatiolle ja lopetatte istunnon, kun olette valmis. Jos istunto-objekti unohtuu välittää, operaatiot suoritetaan transaktion ulkopuolella eikä niitä peruta keskeytyksen yhteydessä.

Istunnon luominen startSession()-metodilla

Kutsukaa client.startSession()-metodia saadaksenne ClientSession-objektin. Tämä ei vielä käynnistä transaktiota, vaan muodostaa ainoastaan palvelimen puolella ylläpidettävän kontekstin. Istunnot voidaan määrittää käyttämään kausaalista yhdenmukaisuutta, jolloin istunnon sisäiset luvut sisältävät aina kaikki saman istunnon aiemmat kirjoitukset myös secondary-solmuilla. Lopettakaa istunto aina finally-lohkossa palvelinresurssien vapauttamiseksi.

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

Transaktion käynnistäminen

Kutsukaa session.startTransaction()-metodia valinnaisten transaktioasetusten kanssa käynnistääksenne usean dokumentin transaktion. Yleisiä asetuksia ovat readConcern (täydelliseen eristykseen yleensä 'snapshot') ja writeConcern (pysyviin vahvistuksiin yleensä { w: 'majority' }). Käynnistämisen jälkeen kaikki operaatiot, joille tämä istunto välitetään, kuuluvat transaktioon ja perutaan, jos transaktio keskeytetään.

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

Istunnon välittäminen operaatioille

Jokaiselle transaktioon sisällytettävälle operaatiolle on välitettävä session-objekti asetuksena. Jos istunto unohtuu välittää operaatiolle, se suoritetaan transaktion ulkopuolella itsenäisenä kirjoituksena, jota ei peruta keskeytyksen yhteydessä. Tämä on yleinen transaktiokoodin virhelähde – tarkistakaa aina, että jokaiselle try-lohkon sisällä olevalle insert-, update- ja delete-operaatiolle välitetään istunto.

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

Vahvistaminen commitTransaction()-metodilla

Kun kaikki operaatiot ovat onnistuneet, kutsukaa session.commitTransaction()-metodia, jotta kaikki muutokset otetaan käyttöön tietokannassa atomisesti. Ennen commit-kutsua muut transaktion operaatiot eivät näe mitään transaktion kirjoituksista. Vahvistuksen yhteydessä MongoDB ottaa kaikki kirjoitukset käyttöön ja vahvistaa ne write concern -asetuksen mukaisesti. Onnistunut vahvistus tarkoittaa, että kaikki transaktion operaatiot on tallennettu pysyvästi.

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;
}

Keskeyttäminen abortTransaction()-metodilla

Jos jokin transaktion operaatio epäonnistuu tai sovelluslogiikka määrittää, ettei transaktiota pidä jatkaa, kutsukaa session.abortTransaction()-metodia. Se peruu kaikki transaktion aikana tehdyt kirjoitukset aivan kuin niitä ei olisi koskaan tehty. MongoDB takaa, ettei osittaista tilaa jää jäljelle – muut lukijat eivät koskaan näe keskeytetyn transaktion kirjoituksia.

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;
}

withTransaction()-apumetodi

Node.js-ohjain tarjoaa kätevän session.withTransaction(fn)-apufunktion, joka käsittelee transaktion aloittamisen, vahvistamisen ja keskeyttämisen automaattisesti sekä tekee automaattiset uudelleenyritykset tilapäisten virheiden yhteydessä. Takaisinkutsufunktio saa parametrinaan istunnon, ja sen tulisi sisältää kaikki transaktion toiminnot. withTransaction-funktion käyttöä suositellaan manuaaliseen aloittamiseen, vahvistamiseen ja keskeyttämiseen verrattuna, koska se käsittelee oikein MongoDB:n edellyttämän uudelleenyrityslogiikan.

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

Transaktion laajuus ja kokoelmat

MongoDB-transaktio voi kattaa useita kokoelmia ja tietokantoja saman klusterin sisällä (sirpaloiduissa klustereissa MongoDB 4.2:sta alkaen). Voit lukea yhdestä kokoelmasta, päivittää toista ja lisätä tietoja kolmanteen – kaikki yhden atomisen transaktion sisällä. Ainoa rajoitus on, että uusia kokoelmia tai indeksejä ei voi luoda usean dokumentin transaktion sisällä. Nämä DDL-toiminnot on suoritettava transaktioiden ulkopuolella.

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 }
  );
});

Transaktiot edellyttävät replikasarjaa

Usean dokumentin transaktiot edellyttävät repl复制asjaa tai sirpaloitua klusteria – ne eivät toimi itsenäisessä MongoDB-instanssissa. Itsenäisessä instanssissa transaktioiden ohjelmointirajapinta on käytettävissä, mutta startTransaction()-funktion kutsu aiheuttaa virheen. Siksi paikallisessa kehitysympäristössä tulisi käyttää paikallista replikaasarjaa (esimerkiksi komennolla mongod --replSet rs0 tai Atlasin maksuttomalla tasolla), jos sovelluskoodisi käyttää transaktioita.

// 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

Transaktion aikakatkaisu ja rajoitukset

MongoDB pakottaa oletusarvoisesti voimaan 60 sekunnin enimmäiskeston transaktiolle (määritettävissä asetuksella transactionLifetimeLimitSeconds). Tätä pidempään kestävät transaktiot keskeytetään automaattisesti. Lisäksi kirjoitustoiminnot voivat käyttää enintään 16 Mt:n oplog-tilaa transaktiota kohden. Pitkään kestävät transaktiot varaavat myös lukituksia ja voivat heikentää samanaikaisten toimintojen suorituskykyä, joten pidä transaktiot lyhyinä ja rajattuina.

Täydellinen siirtoesimerkki validoinnilla

Kootaan kaikki yhteen: täydellinen tuotantokäyttöön sopiva pankkisiirtofunktio, joka käyttää withTransaction-funktiota. Se varmistaa riittävän saldon transaktion sisällä (jolloin toinen kirjoittaja ei ole voinut tyhjentää tiliä saldotarkistuksen ja veloituksen välissä) ja tallentaa tarkastusmerkinnän atomisesti. Tämä malli havainnollistaa kaikkia keskeisiä transaktioiden käsitteitä.

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

Pikatarkistus

Testaa, miten hyvin ymmärrät tämän oppitunnin MongoDB- ja NoSQL-tietokantoja koskevat käsitteet.

Oppitunnin kertaus

Tässä oppitunnissa opit, että transaktiot edellyttävät client.startSession()-funktiolla luotua ClientSession-oliota, jokaiselle transaktion toiminnolle on välitettävä { session }, jotta se sisällytetään transaktioon ja withTransaction() on suositeltu apufunktio, koska se käsittelee uudelleenyrityslogiikan ja siivouksen automaattisesti. Seuraavaksi tutustumme tilapäisten transaktiovirheiden käsittelyyn ja uudelleenyrityslogiikkaan.

Aloita maksutta

Opi JavaScript tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
30
Oppitunnit
120

Usein kysytyt kysymykset

Onko oppitunti ”Istunnon ja usean dokumentin tapahtuman aloittaminen” ilmainen?

Kyllä – oppitunnin ”Istunnon ja usean dokumentin tapahtuman aloittaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko MongoDB Academy-kurssin, päivitä CoddyKit PROhon. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Istunnon ja usean dokumentin tapahtuman aloittaminen”?

Oppijat avaavat ClientSession-istunnon, suorittavat useita toimintoja startTransaction()-funktion sisällä ja vahvistavat tai keskeyttävät tapahtuman. Harjoittelet MongoDB Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni MongoDB Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin MongoDB Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Istunnon ja usean dokumentin tapahtuman aloittaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä MongoDB Academy-oppitunnilla?

Kyllä. Jokainen MongoDB Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. ACID-takuut hajautetussa dokumenttivarastossa
  2. Istunnon ja usean dokumentin tapahtuman aloittaminen
  3. Virheenkäsittely ja uudelleenyrityslogiikka
  4. Tapahtumien suorituskykyyn liittyvät näkökohdat
← Takaisin: MongoDB Academy