Domanda

Ho una tabella semplice con una chiave primaria. La maggior parte delle operazioni di lettura Scarica una riga per il valore esatto della chiave.

I dati in ogni riga mantiene qualche rapporto con righe prima e dopo nell'ordine chiave. Così, quando si inserisce una nuova riga ho bisogno di leggere i 2 file tra i quali si sta per entrare, fare qualche calcolo e quindi da inserire.

La preoccupazione, chiaramente, è che allo stesso tempo un'altra connessione può aggiungere una riga con un valore di chiave nello stesso intervallo. Mi sono coperto se è esattamente lo stesso valore della tonalità secondo inserto fallirebbe, ma se il valore di chiave è differente ma nello stesso intervallo del rapporto può essere rotto.

La soluzione sembra essere per bloccare l'intera tabella per la scrittura quando decido di aggiungere una nuova riga, o (se possibile, che dubito) per bloccare un intervallo di valori chiave. Eppure io preferirei che le operazioni di sola lettura, non sarebbero stati bloccati in quel momento.

Sto usando ODBC con libodbc ++ wrapper per C ++ nel programma client e IBM DB2 versione gratuita (anche se la scelta di DB può ancora cambiare). Questo è quello che ho pensato di fare:

  • avviare la connessione in auto-commit e modalità di isolamento di default
  • quando c'è bisogno di aggiungere una nuova riga, set di auto-commit al modo falso e l'isolamento a serializzato
  • leggere le righe prima e dopo il nuovo valore della chiave
  • di elaborazione e inserire la nuova riga
  • commit
  • di nuovo ritorno al auto-commit e modalità di isolamento di default

Sarà questo fare il lavoro? Saranno altre operazioni essere consentito di leggere allo stesso tempo? Ci sono altri / modi migliori per farlo?

A proposito, non vedo nel libodbc ++ I / F un modo per specificare una transazione di sola lettura. E 'possibile in ODBC?

Edit: Grazie per le risposte molto utili, ho avuto difficoltà a utilizzarlo.

È stato utile?

Soluzione

Se il database è in modalità SERIALIZABLE, non avrete problemi a tutti. Data una chiave K, per ottenere le chiavi precedenti e successivi è necessario eseguire le seguenti query:

select key from keys where key > K order by key limit 1;      # M?
select key from keys where key < K order by key desc limit 1; # I?

I lavori di cui sopra in MySQL. Questa query equivalente funziona in DB2 (dai commenti):

select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);

Il primo set di query fino un blocco di intervallo che impedisce altre operazioni di inserimento di una chiave maggiore di K e minore o uguale a M.

Il secondo insieme di query fino un blocco di intervallo che impedisce altre operazioni di inserimento di una chiave inferiore K e maggiore o uguale a I.

L'indice univoco sulla chiave primaria impedisce K venga inserita due volte. Così si sta completamente coperto.

Questo è ciò che le transazioni sono circa; in modo da poter scrivere il codice come se l'intero database è bloccato.

Nota: Questo richiede un database che supporta vero serializzabilità. Fortunatamente, DB2 fa. che il sostegno vero serializzabilità altri DBMS: SQLServer, e MySQL / InnoDB. DBMS di che non: Oracle, PostgreSQL

Altri suggerimenti

Se il motore di database e di stoccaggio permettono che, si dovrebbe emettere SELECT FOR UPDATE per entrambe le file che si sta tentando di inserire tra i.

questo conflitto con qualsiasi SELECT FOR UPDATE concorrente.

Lo svantaggio è che un blocco di righe 10 e 12 (a inserto 11) impedirà anche selezionando 8 e 10 (a inserto 9).

InnoDB in MySQL può anche inserire un blocco next-key sull'indice, che è serratura del record indice e il divario tra il record successivo.

In questo caso, si avrebbe solo bisogno di emettere un SELECT FOR UPDATE in prima fila, e quindi inserire in concomitanza di fila prima che.

Tuttavia, questo richiede costringendo l'indice e fornendo una condizione range sull'indice che può o può non essere possibile a seconda query.

Il tuo approccio generale è corretta. Ma è necessario utilizzare un'istruzione SELECT che copre le due righe e tutte le possibili righe in mezzo. Ad esempio:

SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10

Nei sistemi di database con blocco pessimistico e la transazione livello di isolamento serializzabile, questa istruzione SELECT dovrebbe impedire le nuove righe da inserire che avrebbe cambiato il risultato della SELECT.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top