Domanda

Ho 2 programmi batch, 1 è un programma che invia e-mail e un altro invia fax. Entrambi accedono a una tabella denominata QUEUE .

Nel programma mittente email, questo è ciò che accade in relazione a QUEUE . Per ogni record in QUEUE che soddisfa i criteri:

  1. Blocca il record 1 nella tabella QUEUE :
    seleziona 1 da QUEUE con (UPDLOCK) dove id = 1
  2. Elaborazione invio tramite e-mail
  3. Elimina il record 1 nella tabella QUEUE:
    elimina da QUEUE dove id = 1
  4. commit commit (la transazione non è auto-commit)

Nel programma mittente fax, si verificano anche passaggi simili, tranne che al passaggio 2, inviamo fax (ovviamente).

Il problema è che a volte l'eliminazione da QUEUE genera un'eccezione che è bloccata. In tal modo, si verifica il reinvio delle e-mail / fax. Sono sicuro che il gruppo di record elaborati da questi programmi non si intersecano.

Sembra che delete cerchi di ottenere un blocco Update (U) su altri record nella tabella sebbene sia necessario eliminare solo un record. Pertanto, si verifica un'eccezione quando altre transazioni hanno blocchi su altri record nella stessa tabella.

Detto questo, devo sapere se esiste un'opzione per rendere " eliminare " l'operazione non acquisisce blocchi sui record diversi da quelli che eliminerà. Perché sembra che il problema sia con " elimina " operazione prendendo blocchi su altri record nella tabella.

A proposito, ecco alcune informazioni sul database (non sono sicuro che possano aiutare):

  • La lettura dell'istantanea confermata è attivata
  • Lo stato di isolamento dello snapshot è attivo
È stato utile?

Soluzione

Hai provato a usare il suggerimento WITH ROWLOCK o WITH NOLOCK sull'istruzione delete?

Hai letto questo articolo ? ti suggerisce di usare (UPDLOCK, READPAST) per prevenire il problema che stai riscontrando

Altri suggerimenti

A volte un blocco si riduce dal blocco di una singola riga al blocco di una sezione di una tabella o al blocco di un'intera tabella. Questo è probabilmente il motivo per cui stai ottenendo blocchi sui record che non stai effettivamente utilizzando nella transazione.

Invece di utilizzare una transazione per bloccare i record, è possibile utilizzare un campo di stato per contrassegnare i record che vengono elaborati.

Esempio:

Blocca alcuni record, quindi ottieni il record che è stato bloccato correttamente:

update queue set status = 'email_processing' where status is null and id = 1
select email, message from queue where status = 'email_processing'

Quando non si utilizza esplicitamente una transazione, ciascuna query viene eseguita nella propria transazione, quindi la query di aggiornamento può modificare in modo sicuro lo stato mentre verifica lo stato corrente nella stessa query.

Al termine dell'invio, eliminare i record:

delete from queue where status = 'email_processing'

Il mittente del fax userebbe ovviamente uno stato diverso (come "elaborazione fax") in modo che i record contrassegnati siano isolati.

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