di: Gian Maria Ricci 14 Gennaio 2009
Come noto, nei sistemi informatici si parla di concorrenza quando più utenti, contemporaneamente, effettuano l'accesso e modificano un database (o in generale una risorsa).
Supponiamo ad esempio di avere un'entità prodotto composta solamente dai campi codice, nome e prezzo; in uno scenario di concorrenza due utenti, Marco e Luigi, visualizzano lo stesso prodotto chiamato "HtmlCup" tramite una pagina Web. Marco effettua un cambiamento al nome prodotto modificandolo in "Html Cup", subito dopo Luigi cambia il prezzo del prodotto, ma quando le sue modifiche vengono inviate al database, la modifica di Marco viene sovrascritta, riportando il nome al valore "HtmlCup".
Questo problema si può facilmente codificare: si aprono due sessioni NHibernate e in ognuna di esse viene caricata la stessa entità, ogni sessione modifica una proprietà e le modifiche vengono propagate al database con il metodo Flush().
La prima modifica viene purtroppo sovrascritta dalla seconda, perché NHibernate, al momento di effettuare il secondo salvataggio, è inconsapevole del fatto che il valore originale è stato nel frattempo modificato. In un simile scenario dove la concorrenza viene ignorata si applica, spesso inconsapevolmente, la soluzione detta last update wins, ovvero: l'ultimo update vince e sovrascrive eventuali modifiche effettuate nel frattempo all'entità.
Listato1 dell'esempio allegato
private static void Listato1()
{ // sessione di Marco
using (ISession session1 = NHSessionManager.GetSession())
{
Product1 prouctLoadedByMarco = session1.Get<Product1>(HtmlCupId);
// sessione di Luigi
using (ISession session2 = NHSessionManager.GetSession())
{
Product1 prouctLoadedByLuigi = session2.Get<Product1>(HtmlCupId);
// Sono Luigi e inserisco uno spazio
prouctLoadedByLuigi.Code = "Html Cup";
session2.Flush(); // Le modifiche vengono propagate
}
prouctLoadedByMarco.Price *= (Decimal)0.9; // Applico uno sconto
// Salvo, ma in questo caso ho sovrascritto le modifiche di Luigi
session1.Flush();
}
// Le modifiche di Luigi non sono più presenti nel database
}
Ora che si conosce il problema è necessario capire come gestirlo, in primo luogo è possibile richiedere un update dinamico di una classe, ovvero generare istruzioni SQL di tipo UPDATE che vanno ad aggiornare solo i campi effettivamente modificati dal momento della lettura. Per far questo basta aggiungere la direttiva dynamic-update="true" nel mapping:
<class name="Product1" table="Products" lazy="false"
dynamic-update="true" >
Eseguendo nuovamente il Listato1() si può notare come le istruzioni di update riguardano ora i soli campi effettivamente modificati, permettendo cosi la modifica concorrente di proprietà differenti. Ecco come si presentano le istruzioni SQL:
NHibernate: UPDATE dbo.Products SET Code = @p0 WHERE Id = @p1; @p0 = 'Html Cup', @p1 = '1' NHibernate: UPDATE dbo.Products SET Price = @p0 WHERE Id = @p1; @p0 = '20.304000', @p1 = '1'
Questa tecnica non è comunque considerata un'effettiva gestione della concorrenza, anche perché non risolve il problema della modifica contemporanea della stessa proprietà. Naturalmente NHibernate integra al suo interno varie metodologie di gestione di concorrenza che possono essere attivate se necessario.
Guida Windows Azure Code SnippetsLe migliori pratiche per far girare le applicazioni "in the cloud",... |
Guida ASP.NET MVC Best PracticesUn workflow dettagliato e ricco di suggerimenti pratici per... |
Guida ASP.NET Starter KitUn modo semplice per imparare ad utilizzare le tecnologie Microsoft... |
Ogni giovedì, direttamente nella tua e-mail: articoli, guide, tutorial e script ASP, ASP.Net, SQL server e IIS.
Iscriviti alla newsletter
|
|
Corso Progettazione database11 Maggio 2012 a Milano |
|
|
Amministratore di Reti Windows Server 200811 Giugno 2012 a Milano |
|
Nessun corso previsto |