Mam pytanie jak programowo w c# obsłużyć transakcje, baza danych to MS
SQL Express, korzystam z DataSetów.
przykładowa transakcja:
1. początek transakcji,
2. wykonuje sprawdzenie czy user o danym loginie istnieje (select),
(po tym kroku nikt nie powinnien móc wywołać funkcji sprawdzającej)
3. jeśli nie było usera o podanym loginie dodaje lub uaktualniam dane
w bazie (update),
4. koniec transakcji,
(dopiero tutaj następny user może wywołać funckje sprawdzającą -
selecta na tabeli).
W rozwiazaniu, którego używam tabela jest blokowana dopiero po
wykonaniu update'a do bazy, ale to jest za późno, ustawiłem też
isolation level na najbardziej restrykcyjny i róznież nic.
Potrzebuje rozwiązania, które zagwarantuje mi, że żaden user nie
odczyta danych z tabeli po wykonaniu się selecta w podanej wyżej
transakcji i dostęp do bazy zostanie zwolniony po zakończeniu
transakcji.
Rozwiązanie musi opierać się na oprogramowaniu DataSetów - aplikacja w
tej chwili z nich korzysta i nie chcę tego zmieniać jedynie dodać
transakcje.
Proszę o pomoc, dobre rady, wskazówki.
Pozdrawiam
? możesz to rozwinąć ?
> Rozwiązanie musi opierać się na oprogramowaniu DataSetów - aplikacja w
nie musi, jeśli to jest kawałek procesu biznesowego w architekturze
trójwarstwowej, to użyj mechanizmu synchronizacji wątków - będzie prościej i
bezpieczniej, w razie wywrotki kodu nie zostaniesz z zablokowanym serwerem
bazy danych, czekającym na zwolnienie blokady przez proces, które nigdy nie
nastąpi.
jeśli to koniecznie musi być po stronie sqla, to próbuj blokadami
aplikacyjnymi (sp_getapplock, sp_releaseapplock).
Wiktor Zychla
> ? możesz to rozwinąć ?
w kodzie wyglada to następująco:
część funkcji dodającej nowego usera
try{
transaction =
sqlConnection.BeginTransaction(IsolationLevel.Serializable);
row = operatorTable.NewOperatorRow();
using (FrmAdminOperator frm = new
FrmAdminOperator(row))
{
//przekazuje transakcje do forms (nie jest to
piękne ale musi zostać), w tej formie jest funkcja sprawdzająca, czy
dany operator (user) istnieje
frm.Transaction = transaction;
frm.Text = "Nowy operator";
if (frm.ShowDialog() == DialogResult.OK)
{
row.EndEdit();
operatorTable.AddOperatorRow(row);
updateRow(row, transaction);
transaction.Commit();
//loguje wykonaną operacje do bazy
log.Log(LogOperacja.Dodanie, row.ID);
}
}
}
catch (Exception ex)
{
transaction.Rollback();
operatorTable.RejectChanges();
Msg.Exception(ex, "Wystąpił podczas dodawania
użytkownika!");
}
fillData();
}
-------------------------------------------------------------------------
funkcja z formy
private bool operatorExists(string login)
{
bool flag = false;
try
{
using (OperatorTableAdapter ta = new
OperatorTableAdapter())
{
ta.Connection = _transaction.Connection;
ta.SetTransaction(_transaction);
//tutaj wywołany zostaje funckaj (select), która
powinna blokować odczyt innym userów, aby nie mogli sprawdzić, czy
user o podanym loginie istnieje,
//ponieważ w innej sesji może właśnie odbywać się
update loginu innego usera
flag = (int)ta.CountByLogin(login) > 0 ? true :
false;
}
return flag;
}
catch {
MsgCollection message = new MsgCollection("W
formularzu wystąpiły błędy");
message.Add(new Msg("Wystąpiły błędy podczas
sprawdzania unikalności loginu!", MsgType.Error));
}
return flag;
}
> > Rozwiązanie musi opierać się na oprogramowaniu DataSetów - aplikacja w
> nie musi, jeśli to jest kawałek procesu biznesowego w architekturze
> trójwarstwowej, to użyj mechanizmu synchronizacji wątków - będzie prościej i
> bezpieczniej, w razie wywrotki kodu nie zostaniesz z zablokowanym serwerem
> bazy danych, czekającym na zwolnienie blokady przez proces, które nigdy nie
> nastąpi.
Zablokowania serwera nie przewidziałem:/
Aplikacja niestety nie jest w architekturze trójwarstwowej, łączy się
bezpośrednio z serwerem baz danych.
Myślałem też o korzystaniu z transactionScope'ów, które działają
dobrze w tej sytuacji, ale nie wiem czy to dobry pomysł?
> jeśli to koniecznie musi być po stronie sqla, to próbuj blokadami
> aplikacyjnymi (sp_getapplock, sp_releaseapplock).
> Wiktor Zychla
Dziękuje i pozdrawiam
myślę o zwykłej synchronizacji wątków w procesie serwera aplikacji. to ma
oczywiście wadę, polegającą na błędnym działaniu w scenariuszu farmy
serwerów aplikacji, ale na jednym serwerze będzie działać jak najbardziej
poprawnie.
Wiktor Zychla
Dziękuje za pomoc.