2011-08-28 8 views
5

Ecco due potenziali flussi di lavoro che vorrei eseguire in un'applicazione web.Come si gestiscono le modifiche simultanee in un'applicazione Web?

Variante 1

  • utente invia richiesta
  • server legge i dati
  • server di modifica i dati
  • server salva modificato dati

Variante 2:

  • utente invia richiesta
  • server legge i dati
  • server invia i dati all'utente
  • utente invia richiesta con modificazioni
  • server salva modificato dati

In ciascuno di questi casi, mi chiedo: quali sono gli approcci standard per garantire che l'accesso concorrente a questo servizio produca risultati sani? (Vale a dire di modifica di nessuno viene clobbered, valori corrispondono ad alcuni ordinamento delle modifiche, ecc)

La situazione è ipotetica, ma qui ci sono alcuni dettagli di dove avrei probabilmente bisogno di affrontare questo in pratica:

  • applicazione web, ma il linguaggio non specificato
  • potenzialmente, utilizzando un framework web
  • archivio di dati è un database relazionale SQL
  • logica applicata è troppo complesso per esprimere bene in una query ad esempio, valore = valore + 1

Mi sento come se preferirei non provare a reinventare la ruota qui. Sicuramente questi sono noti problemi con soluzioni ben note. Si prega di avvisare.

Grazie.

risposta

4

Per quanto a mia conoscenza, non v'è alcuna soluzione generale al problema.

La radice del problema è che l'utente può recuperare i dati e fissarli sullo schermo per un lungo periodo di tempo prima di effettuare un aggiornamento e un salvataggio.

So di tre approcci di base:

  1. Quando l'utente legge il database, bloccare il record e non rilasciano fino a quando l'utente salva eventuali aggiornamenti. In pratica, questo è incredibilmente poco pratico. Cosa succede se l'utente visualizza uno schermo e poi va a pranzo senza salvare? O va a casa per il giorno? O è così frustrato nel tentativo di aggiornare questo stupido disco che lascia e non torna mai più?

  2. Esprimi i tuoi aggiornamenti come delta anziché destinazioni. Per fare un esempio classico, supponiamo di avere un sistema che registra le scorte nell'inventario. Ogni volta che c'è una vendita, devi sottrarre 1 (o più) dal conteggio delle scorte.

Quindi dire che la quantità attuale a disposizione è 10. L'utente A crea una vendita. Quantità corrente = 10. L'utente B crea una vendita. Ottiene anche la quantità corrente = 10. L'utente A inserisce due unità vendute. Nuova quantità = 10 - 2 = 8. Salva. L'utente B entra in una unità venduta. Nuova quantità = 10 (il valore che ha caricato) - 1 = 9. Salva. Chiaramente, qualcosa è andato storto.

Soluzione: invece di scrivere "aggiornamento inventario quantità set = 9 dove itemid = 12345", scrivere "aggiornamento inventario quantità impostata = quantità-1 dove itemid = 12345". Quindi lascia che il database accoda gli aggiornamenti. Questo è molto diverso dalla strategia numero 1, in quanto il database deve solo bloccare il record per un tempo sufficiente a leggerlo, effettuare l'aggiornamento e scriverlo. Non deve aspettare mentre qualcuno fissa lo schermo.

Naturalmente, questo è utilizzabile solo per le modifiche che possono essere espresse come delta. Se, per esempio, stai aggiornando il numero di telefono del cliente, non funzionerà. (Come, il vecchio numero è 555-1234. L'utente A dice di cambiarlo in 555-1235. Questo è un cambiamento di +1 L'utente B dice di cambiarlo in 555-1243. Questo è un cambiamento di +9. +10, il nuovo numero del cliente è 555-1244. :-)) Ma in casi del genere, "l'ultimo utente che fa clic sul tasto Invio vince" è probabilmente il meglio che puoi fare comunque.

  1. In fase di aggiornamento, verificare che i campi pertinenti nel database corrispondano al proprio valore "da". Ad esempio, supponiamo che lavori per uno studio legale per negoziare contratti per i tuoi clienti. Hai una schermata in cui un utente può inserire note sulle negoziazioni. L'utente A visualizza un record del contratto. L'utente B mostra lo stesso record di contratto. L'utente A entra che ha appena parlato con l'altra parte al telefono e sono graditi ai termini proposti. L'utente B, che ha anche provato a chiamare l'altra parte, fa in modo che non stia rispondendo alle telefonate e sospetta che stiano facendo un stonewalling. Un utente fa clic su Salva. Vogliamo che i commenti dell'utente B sovrascrivano l'utente A? Probabilmente no. Invece mostriamo un messaggio che indica che le note sono state cambiate da quando ha letto il record e gli ha permesso di vedere il nuovo valore prima di decidere se procedere con il salvataggio, interrompere o inserire qualcosa di diverso.

[Nota: il forum è rinumerazione automaticamente i miei elenchi numerati. Non sono sicuro di come ignorarlo.]

0

Le cose sono semplici a livello di applicazione - ogni richiesta è servita da un thread diverso (o processo), quindi a meno che non si abbia lo stato nelle classi di elaborazione (servizi), tutto è sicuro.

Le cose diventano più complicate quando si raggiunge il database, vale a dire dove si trova lo stato. Lì hai bisogno di transactions per assicurarti che tutto sia a posto.

Le transazioni hanno un insieme di proprietà - ACID, che "garantiscono che le transazioni del database siano elaborate in modo affidabile".

+0

Grazie. Questo funziona bene per la variazione 1. Ma, qual è il solito modo di affrontare questo in una situazione in cui non si hanno transazioni? per esempio.MyISAM di MySQL – Ming

+0

Per chiarire, immagino che un sacco di software per forum avrebbe dovuto trattare questo tipo di problema. Eppure, vedo che molti di loro usano MyISAM, che non ha transazioni. Qual è la loro risoluzione a questo? – Ming

+0

non puoi gestirlo in modo affidabile. Il software del forum si basa principalmente su inserti e raramente su modifiche simultanee, quindi non causa molti problemi – Bozho

0

Se non si dispone di transazioni in mysql, è possibile utilizzare il comando update per garantire che i dati non siano danneggiati.

UPDATE tableA SET status=2 WHERE status = 1 

Se lo stato è uno, allora solo un processo ben ottenere il risultato che un record è stato aggiornato. Nel codice sottostante, restituisce -1 se l'aggiornamento NON è stato eseguito (se non ci sono state righe da aggiornare).

PreparedStatement query; 
query = connection.prepareStatement(s); 
int rows = -1; 
try 
{ 
    rows = query.executeUpdate(); 
    query.close(); 
} 
catch (Exception e) 
{ 
    e.printStackTrace(); 
} 
return rows; 
Problemi correlati