2010-12-15 9 views
28

Długo się zastanawiałem, dlaczego JDBC API udostępnia tryb automatycznego zatwierdzania (java.sql.Connection.setAutocommit()). Wydaje się, że jest to atrakcyjna niedogodność, która tylko wpędza ludzi w kłopoty. Moja teoria jest taka, że ​​została dodana tylko do JDBC w celu uproszczenia życia dla dostawców, którzy chcieli stworzyć narzędzia do edycji i uruchamiania SQL przy użyciu JDBC. Czy jest jakiś inny powód, aby włączyć autocommit, czy też zawsze jest to błąd?Dlaczego ustawić Autocommit na true?

Odpowiedz

11

Niestety, użycie autocommit jest specyficzne dla bazy danych (podobnie jak zachowanie transakcji). Myślę, że jeśli nie masz globalnej, programowej strategii transakcji, autocommit jest prawdopodobnie lepszy niż po prostu nadzieję, że wszyscy właściwie zamkną/wycofają transakcje.

Mówiąc dla MySQL, możesz automatycznie zostawić autocommit = true, a automatycznie wyłączysz to, gdy BEGIN rozpocznie transakcję. Jedynym powodem, dla którego ustawia się autocommit = false, jest wymuszenie błędu, jeśli ktoś spróbuje rozpocząć transakcję bez BEGIN.

Dla uproszczenia w typowej aplikacji Java + MySQL dzisiaj, mniej lub bardziej zignorowałbym ustawienie automatycznego zatwierdzania, używałbym wzoru otwartej sesji w widoku i nazwałbym go dobrym.

Zdecydowanie odradzam jawne blokady wierszy RDBMS i zamiast nich stosuję optymistyczne blokady. Hibernate oferuje wbudowane wsparcie dla optymistycznych blokad, ale jest łatwy do przyjęcia nawet w przypadku ręcznie zwijanego kodu i oferuje lepszą wydajność.

+2

Aby wyjaśnić typowe Ja va + Aplikacja MySQL: ustaw auto-commit na true. Otwórz sesję (i rozpocznij transakcję) raz, na początku przychodzącego żądania (strona internetowa lub REST/JSON). Jeśli żądanie przetwarza się normalnie, zatwierdz transakcję po zakończeniu przetwarzania żądania. Następnie dodaj rolkę do renderowania strony 500 dla żądania. Zasadniczo tak wygląda na przykład struktura Play. Jest intuicyjny dla użytkownika i programisty. –

+0

To jest dobra odpowiedź - "żądanie internetowe" powinno w dużym stopniu korelować z "transakcją DB" w webappie. Dlatego musimy polegać na optymalizacji, a nie blokowaniu DB. Pomaga w korzystaniu z OpenSessionInView do przechowywania sesji otwartej przez całe żądanie, włącznie z wyświetlaniem renderowania, a następnie opróżnianiem/zatwierdzaniem na końcu żądania. –

+0

Moim zdaniem nie jest to dobra odpowiedź, jeśli typowa aplikacja Java + MySQL to coś więcej niż "projekt na kilka tygodni", należy rozważyć sesję otwartą-w-widoku jako antypodstawkę. Szybko stracisz kontrolę nad tym, co dzieje się w twojej aplikacji, praktycznie upewnisz się, że masz problemy z wydajnością lub współbieżnością, autocommit pozostawi Cię bez limitu czasu transakcji lub limitu czasu transakcji działającego jako "czas oczekiwania na żądanie ogólne". Powiedziałbym, że żądanie internetowe NIE koreluje w transakcji SQL w ponad 90% przypadków. –

5

Tryb zatwierdzania zmienia sposób, w jaki db utrzymuje blokady.

Wskazane jest wyłączenie trybu automatycznego zatwierdzania tylko w trybie transakcji. W ten sposób unikasz trzymania blokad baz danych dla wielu instrukcji, co zwiększa prawdopodobieństwo konfliktów z innymi użytkownikami.

...

Aby uniknąć konfliktów podczas transakcji, DBMS używa blokad, mechanizmy blokowania dostępu przez innych danych, która jest dostępna dla transakcji. (Zauważ, że w trybie auto-commit, gdzie każda wypowiedź jest transakcją, zamki są przechowywane tylko na jednym rachunku.)

http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

Biorąc pod uwagę, że nawet mySQL i DB2 są w wielu wersjach wielowymiarowych, tutorial staje się nieco anachroniczny. :( – Affe

+0

Poziomy izolacji Snapshot nie przychodzą za darmo: http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/overhead-of-row-versioning.aspx Zyskujesz współbieżność dzięki izolacji migawki , ale dodajesz narzut, – hythlodayr

+0

Zrozumienie sposobu, w jaki zdobywasz blokady, zawsze ma znaczenie –

18

jedynym rozsądnym powodem widzę jest pozbyć się connection.commit() i connection.rollback() Płyta podstawowa w prostych transakcjach pojedynczych zapytań w małych aplikacjach. JDBC w surowej postaci wymaga już samo wielu elementów. Każda linia mniej czyni JDBC mniej przerażającym na początek.

3

95% bazy kodu, z którą teraz pracuję, wiąże się z pojedynczymi aktualizacjami, w przypadku których autouzupełnianie jest całkowicie uzasadnione. Więc domyślnie to włączamy. Tylko wyłączając go na tyle długo, aby wykonać sekcje kodu, które muszą być transakcją, autocommit idzie z powrotem!

+0

Należy pamiętać, że transakcja może dać Ci również limit czasu transakcji od menedżera transakcji. Czy ustawiasz limit czasu dla każdego z zapytań? –

8

Prawie zawsze uruchamiam z autocommit = true. W 99% przypadków moje aktualizacje są atomowe. Jasne, są przypadki, w których piszesz debet, a następnie nie możesz zapisać kwoty, którą chcesz przywrócić. Ale z mojego doświadczenia wynika, że ​​są one stosunkowo rzadkie. Zwykle każdy zapis, który piszę, jest samodzielny. W takim przypadku nie ma potrzeby zajmowania się zatwierdzaniem po każdym zapisie. Zapisuje tu i tam linię kodu. Może zaoszczędzić więcej, jeśli, biorąc pod uwagę strukturę programu, oznacza to, że nie potrzebuję dodatkowego bloku try/catch lub, że nie muszę przekazywać obiektu połączenia między funkcjami. To oszczędza denerwujących błędów, w których ktoś zapomniał zrobić commit.

Jedyny sposób, w jaki widzę, że może "zwabić kogoś w tarapaty" to decyzja, że ​​wyłączenie autocommit i wykonanie commitowania lub wycofania jest zbyt dużym kłopotem, więc robi aktualizacje, które powinny być w ramach transakcji indywidualnie. Wtedy wszystko zaczyna działać tak długo, jak nic się nie wydarzy, co powinno przerwać transakcję. Jeśli scenariusze testowe są niewystarczające, mogę sobie wyobrazić, że to wkracza do produkcji.

Ale można powiedzieć to samo o prawie każdej funkcji języka. Przypuśćmy, że napiszesz program, który przetwarza liczby, które w 90% czasu zmieszczą się w długim, ale co jakiś czas może być większy. W obliczu tej sytuacji, właściwym rozwiązaniem jest użycie BigInteger lub stworzenie nowej klasy, aby obsłużyć większe liczby. Leniwy programista może zostać zwabiony do używania długo, ponieważ zwykle będzie działał, a inne alternatywy są zbyt wielkim problemem. Czy można zatem wnioskować, że Java nie powinna zawierać długich (lub int), ponieważ ktoś może zostać zwabiony do korzystania z nich, gdy nie są odpowiednie?

Jeśli w swoich programach większość aktualizacji musi być wykonana w kontekście transakcji, wyłącz automatyczne zatwierdzanie. Jego obecność nikomu nie szkodzi. Jest tam, kiedy jest wygodny, ale kiedy nie jest, możesz go wyłączyć.

+1

Od czasu specyfikacji JDBC 3 połączenia w trybie "automatycznego zatwierdzania" nie mogą mieć otwartych więcej niż jednej instrukcji. Zatem zagnieżdżone UPDATE lub nawet SELECT w zewnętrznej pętli SELECT spowoduje problemy. –

+0

To nie tylko atomowość, transakcja może mieć przypisany limit czasu, jeśli obsługuje go menedżer transakcji. Korzystanie z autocommit i brak limitu czasu zapytania może doprowadzić Cię do niewykrytych problemów z wydajnością SQL, zawieszonych ciężkich zapytań itp. –

+0

Nie używam Javalandu od lat, więc być może nowsze wersje Javy są inne lub po prostu błędnie wymyślam pewne rzeczy. Ale jestem pewien, że dostałem czasy oczekiwania SQL podczas wykonywania kwerend z autocommit. Mam wiele miłych wspomnień związanych z zapytaniami, które znalazłem w środowisku programistycznym, ale przekroczyłem prod. Może domyślne są różne lub coś takiego. W każdym razie poleganie na przekroczeniu limitu czasu informującego o problemie z wydajnością jest bardzo dosadnym narzędziem. – Jay

6

Automatyczne zatwierdzanie jest wygodne; ale wraz ze zmianami specyfikacji JDBC 3, stała się znacznie mniej użyteczna.

Ponieważ połączenia JDBC 3 w trybie "automatycznego zatwierdzania" nie mogą mieć otwartych więcej niż jednej instrukcji. Wykonywanie innego polecenia spowoduje zamknięcie pierwszego - łącznie z dowolnym zestawem wyników.

Tak więc pętla w obrębie SELECT i wydawanie AKTUALIZACJI (lub nawet zagnieżdżonych SELEKTÓW) będzie miała tendencję do niepowodzenia. Wygląda na to, że jest to przestępstwo, aby chcieć zrobić coś, co jest z wynikami twojego zewnętrznego SELECT!


Zresztą zależy od konkretnej wersji sterownika & .. ale w ogóle JDBC 3 Spec wydaje mandat to kłopotliwe zachowanie. Aktualizacja sterowników może również bezpowrotnie "wykryć" to zachowanie.

Dlaczego warto używać funkcji automatycznego zatwierdzania? Początkowo było to pomocne. Jak inne odpowiedzi powiedzieć, JDBC wymaga dużą ilością guff i manipulacja nazwać poprawnie .. JDBC nie jest naprawdę dobrze zaprojektowane API :(


Te dni, to lepiej przy użyciu Hibernate lub wiosną w JdbcTemplate. A jeśli robisz serwlety/aplikacje internetowe, umieść zarządzanie transakcjami (rozpocznij/zakończ) lub sesję hibernacji (powiązaj ją z lokalnym wątkiem) na granicy "Żądania użytkownika". powiązanie połączenia/transakcji na początku żądania ServletRequest i zwrócenie go na końcu.)

Możesz użyć javax.servlet.Filter lub podobnego i związać go do wątku lokalnego, należy statyczny pomocnik je zdobyć lub wymagają go itp

+0

Nie polecaj połączenia/transakcji/sesji powiązanej z wzorcem ANTI żądania internetowego ... jeśli chcesz, aby transakcja obejmowała np.Żądaj przetwarzania, wielostronicowego przetwarzania danych, wysyłania treści do klienta z wolnym połączeniem możesz to zrobić, ale powiedziałbym, że to bardzo zły pomysł w prawie wszystkich przypadkach. –

+0

Dzięki @ PiotrMüller - jakiekolwiek rozumowanie lub referencje? Prawdopodobnie spodziewałbym się, że możesz wymyślić 0,001% przypadek zły dla prawie każdego wzoru, ale prawdopodobnie lepiej będzie odróżnić "pojedyncze problematyczne narożne przypadki" od bycia "prawie wszystkimi przypadkami" - i wtedy dałem to zalecenie (2012), uważam, że była to dobra rada. Granica żądania użytkownika jest najbardziej podstawową i ważną granicą w aplikacji obsługującej HTTP. Z tego powodu jest to solidny i oczywisty kandydat do projektowania. Każde alternatywne rozwiązanie byłoby prawdopodobnie bardziej złożone. –

+0

w aplikacji internetowej będzie obowiązywać większość wspomnianych "przypadków" (dla każdej typowej aplikacji internetowej). Po włączeniu sesji należy zapewnić wiele aspektów technicznych, którymi należy się zająć natychmiast, np. buforowanie odpowiedzi: upewnij się, że transakcja i połączenie SQL nie są rozpięte przez cały czas połączenia klienta, ciągnąc odpowiedź (dlaczego trzymać połączenie SQL przez długi czas, jeśli klient ma niską przepustowość). Również to bardzo szybko prowadzi do problemów związanych z projektowaniem/wydajnością, jeśli aplikacja rosnąć. W przypadku krótkiego, kilkunastotygodniowego projektu może to być pewne rozwiązanie, ale nie polecałbym go z niczym dużym. –

2

Dobrze istnieją pewne warunki, które wymaga starannego wyglądu umożliwiając jednocześnie „auto-commit” na poziomie globalnym:

a.) Zarządzanie transakcjami na poziomie zapytań będzie pozostawione użytkownikowi, dla instancji, jeśli potrzebna jest garść zapytań, aby odnieść sukces lub razem się nie powiedzie, to musi być opakowana pod BEGIN i zatwierdzić Transakcję.

b.) Pamiętaj, że nie ma przywracania, gdy włączone jest "automatyczne zatwierdzanie".

c.) Istnieje również obciążenie związane z pisaniem (zatwierdzaniem) każdej transakcji.

d.) W przypadku zapytań do odczytu nie ma wyraźnej potrzeby "automatycznego zatwierdzania", ale włączenie "automatycznego zatwierdzania" jest automatycznie wymuszane dla wszystkich zapytań.

Jeśli blokowanie tabel jest jedynym problemem związanym z włączeniem automatycznego zatwierdzania, może to nie być dobry pomysł, ale można skorzystać z niższych limitów czasu blokady.

Powiązane problemy