2009-08-13 13 views
7

Zawsze używałem JDBC w JavaSE w środowisku jednowątkowym. Ale teraz potrzebuję użyć puli połączeń i pozwolić wielu wątkom na interakcję z bazą danych (MSSQL i Oracle) i mam trudności z jej próbowaniem, ponieważ wydaje mi się, że brakuje mi fundamentalnego niedostosowania API.Podstawowe pojęcia JDBC, łączenie i gwintowanie

AFAIK po połączeniu i zalogowaniu Connection reprezentuje fizyczne połączenie tcp/ip z bazą danych. Tworzy Statement (s), które mogą być postrzegane jako interakcja (e) SQL z bazą danych za pomocą Connection.

  • Skąd bierze się transakcja i wycofanie? Czy to na poziomie Connection lub Statement.
  • Czy to bezpieczne, że "jeden" Connection tworzy N wypowiedzi i nadaje je różnym wątkom, aby każdy mógł korzystać z tego Statement?

Jeśli nie, a po skonfigurowaniu basen coś takiego:

OracleDataSource ods = new OracleDataSource(); 
ods.setURL("jdbc:oracle:thin:@tnsentryname"); 
ods.setUser("u"); 
ods.setPassword("p"); 
  • BTW, gdzie mogę ustawić połączenia wielkość puli?

  • Czy to jest to, co bym robił w każdym wątku, aby poprawnie korzystać z połączenia?

// THEAD metoda run

Connection conn = ods.getConnection(); 
Statement stmt = conn.createStatement(); 
ResultSet rs = stmt.executeQuery("the sql"); 
// do what I need to do with rs 
rs.close(); 
int updateStatus = stmt.executeUpdate("the update"); 
stmt.close(); 
conn.close(); 

// koniec nici metoda run

  • Jeśli jakakolwiek fizyczna Podłączenie Pool jakoś awarii lub disconects będzie pula automatycznie próbować ponownie połączyć i wstrzyknąć nowe połączenie w puli, aby kolejne pool.getConnection() po prostu uzyskać połączenie zdrowia?

Bardzo dziękuję i wybacz mój zły angielski.

Odpowiedz

6

Pule połączeń dekorują instancje połączeń i wyciągów za pomocą własnych implementacji wrapperów. Kiedy wywołujesz zamknięcie połączenia, właśnie zwalniasz je z powrotem do puli. Kiedy wywołujesz zamknięcie na przygotowanym wyciągu, faktycznie zwalniasz go z powrotem do pamięci podręcznej instrukcji połączenia. Podczas przygotowywania instrukcji może właśnie pobierać buforowane wystąpienie instrukcji z połączenia. Wszystko to jest ukryte, żebyś nie musiał się tym martwić.

Po nawiązaniu połączenia z klientem nie jest on dostępny dla żadnego innego klienta, który będzie mógł go użyć do momentu przywrócenia połączenia z pulą. Generalnie wystarczy pobrać połączenia, gdy są potrzebne, a następnie zwrócić je, gdy tylko skończysz. Ponieważ połączenia są utrzymywane otwarte w puli, pobieranie i zwalnianie połączeń jest niewielkie.

Powinieneś używać połączenia z puli tak samo, jak z pojedynczym połączeniem JBDC i postępować zgodnie z najlepszymi praktykami dotyczącymi zamykania zasobów, aby nie przeciekać żadnych połączeń ani wyciągów. Zobacz przykłady try/catch/finally w niektórych innych odpowiedziach.

Pule mogą zarządzać zasobami połączenia i przetestować je przed przekazaniem klientom, aby upewnić się, że nie są nieaktualne. W razie potrzeby pula stworzy i zniszczy połączenia.

+0

Wow !, dziękuję teabot jeszcze jedno, gdy już masz połączenie.Dlaczego api dzieli operacje, które mają być wykonane w bazie danych, w obiekcie Statement, a nie tylko za pomocą obiektu połączenia? Opowiadam się za przygotowanymi oświadczeniami. Ale w przypadku normalnych stwierdzeń, czy jest to tylko pozwolenie programistom na powiedzenie N operacji, które migth zostaną wykonane, czy nie, lub mogą być wykonywane wiele razy, po prostu? –

+3

Po prostu zgaduję, ale: jak najwyraźniej zdajesz sobie sprawę, PreparedStatements muszą być oddzielone od połączeń, ponieważ może istnieć więcej niż jedno PreparedStatement dla połączenia. Przypuszczam więc, że ludzie z języka Java wypowiadali instrukcje oddzielnie, aby zachować je równolegle z PreparedStatements. W przeciwnym razie miałbyś cały szereg "funkcji instrukcji" w Połączeniu, a potem jeszcze jeden cały pakiet w PreparedStatement. To zepsułoby drzewo dziedziczenia Statement i PreparedStatement. Jak mówię, po prostu spekulacje. Jeśli ktokolwiek ma autorytatywne źródło, byłbym rozbawiony, gdyby to usłyszał. – Jay

3
  1. Transakcje odbywają się na poziomie połączenia.

  2. Nie. Zazwyczaj sterownik JDBC upewnia się, że nie można wykonać drugiej instrukcji za pośrednictwem tego samego połączenia, gdy inny jest aktywny.

Jeśli potrzebujesz połączenia z puli, spróbuj DBCP framework. Oferuje całkiem przyzwoitą obsługę awarii (np. Zauważając nieaktualne połączenia i połączenia, które nie zostały zwrócone przez kod klienta).

chodzi o kodzie: Zawsze owinąć kod w try{...}finally{...}:

Connection conn = null; 
Statement stmt = null; 
ResultSet rs = null; 
try { 
    conn = ds.getConnection(); 
    stmt = ... 
    rs = ... 
} 
finally { 
    rs = close (rs); 
    stmt = close (stmt); 
    conn = close (conn); 
} 

public static Connection close (Connection conn) { 
    if (conn != null) { 
     try { 
      conn.close(); 
     } 
     catch (SQLException e) { 
      e.printStackTrace(); // Log, don't rethrow!! 
     } 
    } 
    return null; 
} 

Kod ten będzie upewnić się, że wszystkie połączenia, itp, zawsze są prawidłowo zamknięte i że każdy wyjątek podczas blisko nie ukryje poprzedni błąd.

+0

o chłopcze, kocham java, everithing ma ramy: D Dzięki Aaron za odpowiedź. Ale cóż, o tym, co robi szkielet z nieaktualnymi połączeniami, czy nie jest to coś, co powinna implementować domyślnie każda implementacja puli (oracle lub sterownik mssql)? –

+1

"should"! = "Does"! = "Does well". Możesz ustawić limit czasu w DBCP, który mówi: "Jeśli połączenie nie zostało zwrócone po godzinie, wystąpił błąd w kliencie, więc użyjmy go ponownie". Jeśli chodzi o "nieaktualne", musisz podać niestandardowy kod SQL, aby sprawdzić, czy połączenie jest martwe. Byłoby miło, gdyby JDBC zdefiniował to, ale tak nie jest i większość sprzedawców DB nie radzi sobie nawet z obsługą specyfikacji JDBC. Na przykład w Oracle TIMESTAMP nie jest plikiem java.sql.Timestamp. –

2

Myślę, że powinieneś zacząć od Słońca tutorial w sprawie łączenia połączeń. Poza tym istnieje wiele implementacji łączenia połączeń, niektóre open source, w tym one from Apache. Naprawdę powinieneś zacząć od tego, zamiast odkrywać koło.

+0

Em, przepraszam, nie miałem zamiaru ponownie wymyślać czegoś. Samouczek sugeruje opakowanie JDCConnectionManager. Ale sterowniki, których używam, mają już wspólną implementację źródła danych. –

+0

Z jakich sterowników korzystasz? A także, czy spojrzałeś na implementację Apache? Jeśli potrzebujesz czegoś więcej niż podstawowy JDBC, może to rozwiązać Twój problem. – Yishai

+0

ojdbc14.jar i jtds-1.2.2.jar. Dlaczego miałbym wypróbować implementację puli Apache, jeśli sterownik ją już dostarcza? –

1

Możesz zachować tylko jedno Oświadczenie otwarte dla danego połączenia. Stworzenie więcej niż jednego połączenia przy użyciu puli połączeń nie jest trudne, chociaż najlepszym sposobem jest użycie jednego z większych używanych.

Ponadto, jeśli masz zamiar pójść drogą standardowego JDBC, zalecam używanie PreparedStatement zamiast Statement.

Używam iBatis i po wyjęciu z pudełka jest całkiem niezły. Przynosi także kilka innych rzeczy do stołu.

0

dodatkowych bitów:

  1. Serwer aplikacji zazwyczaj oferują zestawianie połączeń, a to może być dość sprytny Jeśli używasz serwera aplikacji zbadać dokładnie. co masz na polu przed dodaniem czegoś własnego

  2. Transakcje:. jeśli masz

    rozpocząć transakcji

    get connnection praca ścisły związek // co oznacza powrót do basenu

    połączenia Get (z tego samego poziomu izolacji itd.)
    // dostaniesz SAME połączenia zastrzega ją dla danej transakcji basen

    pracę // dzieje się w tym samym transacction blisko połączenia

    dokonać transakcji // zobowiązuje wszystkie prace

  3. Połączenia i błędy

Implementacje puli mogą być sprytne. Jeśli którekolwiek połączenie z puli doświadcza pewnych błędów, które wskazują, że serwer DB odskoczył, wtedy pula może wybrać odrzucenie wszystkich członków puli.

7

Jeśli opanowałeś JDBC z pojedynczym gwintowaniem, przechodzenie do wielowątkowych i pul połączeń nie powinno być wielkim problemem. Wszystko, co musisz zrobić inaczej, to: 1. Gdy potrzebujesz połączenia, pobierz je z puli zamiast bezpośrednio. 2. Każdy wątek powinien mieć własne połączenia.

Aby wyjaśnić punkt 2: Jeśli otrzymasz połączenie, a następnie przekażesz je do wielu wątków, możesz mieć dwa wątki próbujące wykonywać kwerendy z tym samym połączeniem w tym samym czasie. Java będzie zgłaszać wyjątki. Możesz mieć tylko jedną aktywną instrukcję dla połączenia i jedną aktywną kwerendę (tj. Zestaw wyników) dla każdego wyciągu. Jeśli dwa wątki trzymają ten sam obiekt połączenia, prawdopodobnie szybko naruszyją tę regułę.

Jeszcze jedno zastrzeżenie: w przypadku łączenia połączeń należy bardzo uważać, aby zawsze zamykać połączenia, gdy skończysz. Menedżer puli nie ma jednoznacznego sposobu, aby wiedzieć, kiedy skończysz połączenie, więc jeśli nie uda ci się go zamknąć, będzie siedzieć tam przez długi czas, być może na zawsze, zależnie od menedżera basenu. Zawsze zawsze podążam za każdym "getConnection" z blokiem try i zamykam połączenie w bloku finally. Potem WIEM, że zamknąłem go, zanim funkcja się zakończy.

Poza tym wszystko powinno być takie samo, jak przywykłe.

+1

+1 Za ostrzeżenie – Everyone

+0

Nie wiem, czy to problem z wersją, "Java będzie zgłaszać wyjątki" nie jest prawdą w ostatnim JDBC. – yuxh

+0

@yuxh Przepraszam, domyślam się, że moje oświadczenie było niejednoznaczne. Nie miałem na myśli, Jeśli spróbujesz to zrobić, Java natychmiast i automatycznie rzuci wyjątek. Miałem na myśli, że jesteś w stanie stworzyć sytuację, która spowoduje wyjątek. MOŻESZ uzyskać odpowiedni sposób na każdym biegu danej aplikacji. – Jay