← Tilbage til koncepter

Database Transactions

Teori

En logisk enhed af arbejde der grupperer flere database operationer til en atomic unit med ACID garantier.

Beskrivelse

Database transactions er fundamentale for at sikre data integritet i multi-user database systemer. En transaktion er en sekvens af operationer der udføres som en enkelt logisk unit of work - enten succeeder alle operationer, eller ingen af dem gør. Dette 'alt eller intet' princip kaldes atomicity. Transactions følger ACID properties: Atomicity (alt eller intet), Consistency (databasen går fra en valid state til en anden valid state), Isolation (concurrent transactions påvirker ikke hinanden), og Durability (committed changes overlever system crashes). Transactions starter med BEGIN eller START TRANSACTION, indeholder en eller flere SQL statements (INSERT, UPDATE, DELETE, SELECT), og slutter med enten COMMIT (gem ændringer permanent) eller ROLLBACK (fortryd alle ændringer). Savepoints tillader partial rollback indenfor en transaktion. Transactions er kritiske i scenarios som bank transfers (debit fra én konto, credit til anden - begge skal ske), inventory management (tjek stock, reducer quantity - skal være atomic), og booking systems.

Problem

Uden transactions kan database operationer fejle midway, efterladende databasen i en inconsistent state. For eksempel: hvis en bank transfer fejler efter debit men før credit, er penge tabt. Concurrent users kan også se partial updates eller overskrive hinandens ændringer.

Løsning

Transactions grupperer relaterede operationer og garanterer at enten alle succeeder (COMMIT) eller alle fortrudes (ROLLBACK). Dette sikrer data consistency selv ved failures. Isolation levels kontrollerer hvordan concurrent transactions ser hinandens changes.

Eksempel

-- Klassisk bank transfer eksempel
BEGIN TRANSACTION;

-- Tjek om der er nok balance
SELECT balance FROM accounts WHERE account_id = 123;
-- Antag balance er 1000

-- Deduct fra sender
UPDATE accounts 
SET balance = balance - 500 
WHERE account_id = 123;

-- Add til receiver
UPDATE accounts 
SET balance = balance + 500 
WHERE account_id = 456;

-- Hvis begge updates succeed:
COMMIT;

-- Hvis noget fejler:
-- ROLLBACK;

-- E-commerce inventory eksempel
BEGIN TRANSACTION;

-- Tjek stock
SELECT stock FROM products WHERE product_id = 789;
-- Antag stock = 10

IF stock >= quantity_ordered THEN
  -- Reducer stock
  UPDATE products 
  SET stock = stock - 3 
  WHERE product_id = 789;
  
  -- Opret order
  INSERT INTO orders (customer_id, product_id, quantity) 
  VALUES (101, 789, 3);
  
  COMMIT;
ELSE
  ROLLBACK;
END IF;

-- Savepoints (partial rollback)
BEGIN TRANSACTION;

INSERT INTO users (name) VALUES ('User 1');
SAVEPOINT sp1;

INSERT INTO users (name) VALUES ('User 2');
SAVEPOINT sp2;

INSERT INTO users (name) VALUES ('User 3');

-- Rollback til sp2 (kun User 3 fortrudes)
ROLLBACK TO SAVEPOINT sp2;

COMMIT; -- User 1 og 2 gemmes

-- Node.js med SQL transaction
const connection = await pool.getConnection();

try {
  await connection.beginTransaction();
  
  // Multiple operations
  await connection.query(
    'UPDATE accounts SET balance = balance - ? WHERE id = ?',
    [amount, fromAccount]
  );
  
  await connection.query(
    'UPDATE accounts SET balance = balance + ? WHERE id = ?',
    [amount, toAccount]
  );
  
  // Log transfer
  await connection.query(
    'INSERT INTO transfers (from_account, to_account, amount) VALUES (?, ?, ?)',
    [fromAccount, toAccount, amount]
  );
  
  await connection.commit();
  console.log('Transfer successful');
  
} catch (error) {
  await connection.rollback();
  console.error('Transfer failed, rolled back:', error);
  throw error;
  
} finally {
  connection.release();
}

-- MongoDB transactions (replica set required)
const session = client.startSession();

try {
  session.startTransaction();
  
  await accountsCollection.updateOne(
    { _id: fromAccountId },
    { $inc: { balance: -amount } },
    { session }
  );
  
  await accountsCollection.updateOne(
    { _id: toAccountId },
    { $inc: { balance: amount } },
    { session }
  );
  
  await session.commitTransaction();
  
} catch (error) {
  await session.abortTransaction();
  throw error;
  
} finally {
  await session.endSession();
}

Fordele

  • Data consistency garanteret
  • Atomicity - alt eller intet
  • Recovery fra failures
  • Concurrent access kontrol
  • Audit trail muligheder

Udfordringer

  • Performance overhead (locking)
  • Deadlocks kan opstå
  • Long-running transactions kan blokere andre
  • Kompleksitet i distributed systems
  • Memory og log overhead

Anvendelsesområder

  • Financial transfers og payments
  • E-commerce order processing
  • Inventory management
  • Booking systems (flights, hotels)
  • Multi-step data modifications

Eksempler fra den virkelige verden

  • Bank transfers (debit og credit skal begge ske)
  • Online shopping (reduce stock, create order, charge card)
  • Flybooking (reserve seat, create booking, send confirmation)
  • Payroll processing (update multiple accounts atomically)
  • Double-entry accounting systems