Vai al contenuto principale
Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Transazioni

Creazione e utilizzo delle transazioni

Le transazioni vengono create utilizzando DataSource o EntityManager. Esempi:

await myDataSource.transaction(async (transactionalEntityManager) => {
// execute queries using transactionalEntityManager
})

oppure

await myDataSource.manager.transaction(async (transactionalEntityManager) => {
// execute queries using transactionalEntityManager
})

Tutte le operazioni da eseguire in una transazione devono essere contenute in una callback:

await myDataSource.manager.transaction(async (transactionalEntityManager) => {
await transactionalEntityManager.save(users)
await transactionalEntityManager.save(photos)
// ...
})

La restrizione più importante quando si lavora in una transazione è UTILIZZARE SEMPRE l'istanza fornita dell'entity manager - transactionalEntityManager in questo esempio. NON UTILIZZARE L'ENTITY MANAGER GLOBALE. Tutte le operazioni DEVONO essere eseguite utilizzando l'entity manager transazionale fornito.

Specifica del livello di isolamento

È possibile specificare il livello di isolamento per la transazione fornendolo come primo parametro:

await myDataSource.manager.transaction(
"SERIALIZABLE",
(transactionalEntityManager) => {},
)

Livelli di isolamento supportati

Le implementazioni dei livelli di isolamento non sono agnostiche tra tutti i database. Ogni driver dichiara quali livelli supporta, e TypeORM genererà un errore se si richiede un livello non supportato.

CockroachDB

  • READ COMMITTED — requires the cluster setting sql.txn.read_committed_isolation.enabled, which is enabled by default in recent versions
  • REPEATABLE READ — requires the cluster setting sql.txn.repeatable_read_isolation.enabled, which is disabled by default (introduced in v24.3.0)
  • SERIALIZABLE (default)

CockroachDB maps weaker SQL isolation requests to stronger levels. The fallback behavior depends on the corresponding cluster settings. For example, when you request READ UNCOMMITTED, READ COMMITTED or REPEATABLE READ via SQL (e.g. BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED), CockroachDB accepts the syntax and may run the transaction at a stricter level instead:

  • READ COMMITTED → runs as:
    • SERIALIZABLE if sql.txn.read_committed_isolation.enabled is false and sql.txn.repeatable_read_isolation.enabled is false
    • REPEATABLE READ if sql.txn.repeatable_read_isolation.enabled is true and sql.txn.read_committed_isolation.enabled is false
  • READ UNCOMMITTED → runs as:
    • SERIALIZABLE if sql.txn.read_committed_isolation.enabled is false and sql.txn.repeatable_read_isolation.enabled is false
    • READ COMMITTED if sql.txn.read_committed_isolation.enabled is true
    • REPEATABLE READ if sql.txn.repeatable_read_isolation.enabled is true and sql.txn.read_committed_isolation.enabled is false
  • REPEATABLE READ → runs as SERIALIZABLE if sql.txn.repeatable_read_isolation.enabled is false

Livello di isolamento predefinito

Puoi configurare un livello di isolamento predefinito per tutte le transazioni impostando isolationLevel nelle opzioni di DataSource:

const dataSource = new DataSource({
type: "postgres",
isolationLevel: "SERIALIZABLE",
// ...
})

Una volta impostato, tutte le transazioni avviate senza un livello di isolamento esplicito utilizzeranno questo predefinito. Un livello di isolamento esplicito passato a transaction() o startTransaction() sovrascriverà il predefinito.

Utilizzo di QueryRunner per creare e controllare lo stato di una connessione database singola

QueryRunner fornisce una singola connessione al database. Le transazioni vengono gestite tramite i query runner. È possibile stabilire una singola transazione solo su un singolo query runner. Puoi creare manualmente un'istanza di query runner e utilizzarla per controllare manualmente lo stato della transazione. Esempio:

// create a new query runner
const queryRunner = dataSource.createQueryRunner()

// establish real database connection using our new query runner
await queryRunner.connect()

// now we can execute any queries on a query runner, for example:
await queryRunner.query("SELECT * FROM users")

// we can also access entity manager that works with connection created by a query runner:
const users = await queryRunner.manager.find(User)

// lets now open a new transaction:
await queryRunner.startTransaction()

try {
// execute some operations on this transaction:
await queryRunner.manager.save(user1)
await queryRunner.manager.save(user2)
await queryRunner.manager.save(photos)

// commit transaction now:
await queryRunner.commitTransaction()
} catch (err) {
// since we have errors let's rollback changes we made
await queryRunner.rollbackTransaction()
} finally {
// you need to release query runner which is manually created:
await queryRunner.release()
}

Esistono 3 metodi per controllare le transazioni in QueryRunner:

  • startTransaction - avvia una nuova transazione all'interno dell'istanza del query runner.

  • commitTransaction - consolida tutte le modifiche apportate utilizzando l'istanza del query runner.

  • rollbackTransaction - annulla tutte le modifiche apportate utilizzando l'istanza del query runner.

Ulteriori informazioni su Query Runner.