2011-01-07 12 views
6

Używam Spring.NET i NHibernate przez kilka lat i jestem bardzo zadowolony. Jednak zawsze grałem z wieloma wątkami, rozszerzeniami reaktywnymi i wreszcie z Task Parallel Library, która jest świetną strukturą. Niestety wszystkie podejścia wielowątkowe zawodzą w związku z sesją NHiberntate, która nie jest bezpieczna dla wątków.C# zadanie Biblioteka równoległa i NHibernate/Spring.NET

Pytam cię, w jaki sposób mogę korzystać z programowania równoległego i nadal korzystać z NHibernate.

Na przykład: Mam CustomerRegistrationService klasę, która metoda Register wykonuje kilka zadań:

ICustumer customer = this.CreateCustomerAndAdresses(params); 
this.CreateMembership(customer); 
this.CreateGeoLookups(customer.Address); 
this.SendWelcomeMail(customer); 

Dwie ostatnie metody byłyby idealnymi kandydatami do biegną równolegle, CreateGeoLookups nazywa niektórych usług internetowych w celu ustalenia geo lokalizacji Klienta adres i tworzy nowe jednostki, a także aktualizuje samego klienta. SendWelcomMail robi to, co mówi.

Ponieważ CreateGeoLookups używa NHibernate (chociaż przez obiekty repozytorium, więc NHibernate jest ostro ukryty przez Interfaces/Dependency Inection) nie będzie działać z Task.Factory.StarNew (...) lub innymi mechanizmami Threading.

Moje pytanie nie dotyczy rozwiązania tego problemu, który opisałem, ale chciałbym usłyszeć od ciebie o metodach NHibenrate, Spring.NET i równoległych.

Dziękuję bardzo Max

Odpowiedz

8

W NH Jego ISession, który nie jest bezpieczny wątku, ale ISessionFactory jest całkowicie bezpieczny wątku, łatwo wspieranie co wydaje jesteś po. Jeśli zaprojektowałeś zarządzanie cyklem życia sesji (i repozytoriami zależnymi od niego) w taki sposób, abyś przyjmował jedną spójną ISIS dla połączeń, wtedy tak, będziesz miał tego rodzaju kłopoty. Ale jeśli zaprojektowałeś swój schemat obsługi sesji, aby założyć tylko jedną instancję ISessionFactory, ale nie przyjmowałeś założeń dotyczących ISession, to nic nie powstrzymuje cię od interakcji z NH równolegle.

Chociaż nie wspomniałeś o tym, że Twój przypadek użycia jest używany w Internecie, ważne jest, aby wziąć pod uwagę to, że w przypadku korzystania z web-centric (np. Co jest dość częstym przypadkiem dla użytkowników Spring.NET, jak również wiele innych frameworków zarządzających NH), często używany wzorzec zarządzania sesją (nazywane często w Spring.NET "otwartą sesją w widoku" lub po prostu "OSIV") NIE będzie działał, a Ty będzie musiał przejść na inny okres trwania cyklu życia ISession. Dzieje się tak, ponieważ (jak sugeruje nazwa) wzorzec sesja-na-żądanie/OSIV czyni (teraz niepoprawnym w twoim przypadku) założeniem, że istnieje tylko jedna instancja ISession na czas każdego HttpRequest (i prawdopodobnie chciałbyś być odradzanie tych równoległych połączeń NH w kontekście pojedynczego HttpRequest w przypadku korzystania z sieci).

Oczywiście w przypadku nieinternetowym, w przypadku którego rzadko występuje pojęcie podobne do sesji na żądanie, nie byłoby tak prawdopodobne, że napotkano by ten problem, ponieważ zarządzanie cyklem życia sesji rzadko jest tak trudne/krótkotrwałe jak w aplikacjach internetowych.

Mam nadzieję, że to pomoże.

-Steve B.

0

Dziękuję za odpowiedź. Wiem, że "ISIZA, która nie jest bezpieczna dla wątków, ale ISessionFactory jest całkowicie bezpieczna dla wątków". Moim problemem w powyższym kodzie jest na przykład to, że cała operacja jest opakowana w jedną transakcję. Tak więc this.CreateCustomerAndAdresses (params) w głównym wątku # 1 użyje na przykład ISession nr 1 z transakcją nr 1.Wywołanie pozostałych trzech równolegle spowoduje utworzenie trzech kolejnych wątków i trzech kolejnych sesji i transakcji, co prowadzi do przekroczenia limitu czasu bazy danych w moim przypadku. Zakładam, że transakcja nr 1 nie została pomyślnie zatwierdzona, ponieważ oczekuje na zakończenie trzech współbieżnych zadań. Jednak trzy równoległe zadania próbują odczytać z bazy danych, gdy transakcja jest nadal aktywna, co prowadzi do zakleszczenia/przekroczenia czasu.

Czy jest jakiś sposób, aby powiedzieć innym wątkom/sesjom, że nie można utworzyć nowej transakcji, ale użyć głównej transakcji nr 1?

Używam TxScopeTransactionManager z Spring.NET, który wykorzystuje DTC (System.transactions). Mam google'ować, że być może System.Transactions.DependentTransaction może działać, ale nie mam pojęcia, jak zintegrować go w moim scenariuszu zarządzanym transakcjami Spring.NET.

Dzięki

+0

Naprawdę powinieneś edytować swoje główne pytanie z tym pytaniem. Czy któryś z nich zadziałał jako odpowiedź? – paqogomez

2

Jest to trudna rzecz, o którą prosisz. DTC należy traktować ostrożnie.

Jedyne rozwiązanie, jakie mogę wiedzieć, to korzystanie z niezawodnych wiadomości transakcyjnych (np. MSMQ + NServiceBus/MassTransit).

Taki wzór umożliwia to. to będzie wyglądać następująco:

var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid}); 

Następnie można używać dwóch programów obsługi zdarzeń (reaktorów), które obsłużyć zdarzenia i wysłać e-mail lub tworzenia wyszukiwań.

Nie umożliwi to współdzielenia Transakcji, ale zapewni działanie Reaktorów (w nowej Transakcji) po uzyskaniu większej liczby klientów. Również to nie ma nic wspólnego z OC.

+0

W przypadku zadanego problemu uważam, że jest to rozsądniejsze podejście. Nie chcesz nie tworzyć klienta, ponieważ nie możesz utworzyć danych geograficznych lub wysłać e-maila, zamiast tego chcesz powtórzyć oba te procesy, dopóki ich nie ukończą. Jest to idealne dopasowanie do architektury kolejki wiadomości. –