W przypadku aplikacji współpracuj?cych z baz? danych należy rozważyć kwestie wydajno?ci
zapytań wysyłanych do bazy danych, odpowiedniego projektu bazy danych oraz odpowiedniego
projektu aplikacji.<br><br>
Pula poł?czeń<br>
W przypadku aplikacji standalone pula poł?czeń nie jest nam potrzebna i nie poprawi wydajno?ci
naszej aplikacji. W Przypadku aplikacji internetowej natomiast użycie puli poł?czeń niekiedy
może drastycznie polepszyć wydajno?ć. Pula poł?czeń jest magazynem kilku poł?czeń do bazy danych
z których aplikacji korzysta podczas swojej pracy. Aby zrozumieć zalety użycia puli poł?czeń
postaram się tu przedstawić dwie wersje aplikacji, jedna bez puli, a drug? z pul? poł?czeń.
WyobraĽmy sobie aplikacje internetowa, która po kliknięciu na link w przegl?darce wykonuje jakie?
operacje na bazie danych. W wersji bez puli poł?czeń po kliknięciu aplikacja ł?czy się z baz?
danych, a dopiero następnie wykonuje operacje na bazie danych. W przypadku aplikacji z pul?
poł?czeń po kliknięciu aplikacja nie ł?czy się z baz? danych, tylko z puli poł?czeń pobiera
już istniej?ce poł?czenie do bazy danych i na tym poł?czeniu wykonuje operacje na bazie danych.
Pula poł?czeń najczę?ciej inicjowana jest na starcie aplikacji i wtedy następuje taka ilo?ć
poł?czeń na jak? skonfigurowana jest pula poł?czeń. Standardowa implementacja puli poł?czeń
polega na uruchamianiu podczas startu pewnej ilo?ci poł?czeń (warto?ć startowa). Je?li aplikacja
podczas pracy zaż?da poł?czenia z puli poł?czeń poł?czenie z puli do aplikacji jest zwracane,
następnie aplikacja na tym poł?czeniu wykonuje operacje na bazie i kiedy poł?czenie nie
jest już potrzebne poł?czenie to zwraca do puli poł?czeń.
a wielko?ć puli zmniejsza się o jeden. W przypadku je?li pula poł?czeń jest pusta aplikacja
zazwyczaj dokonuje jeszcze kilku prób pobrania poł?czenia z puli i je?li to nie pomoże, to
zwraca bł?d. Pula może być pusta ponieważ może tak się stać, że jednocze?nie będziemy mieli wiele
ż?dań operacji na bazie danych i przy kolejnym ż?daniu może się okazać iż w danej chwili
wszystkie poł?czenia s? używane.<br><br>
Klasa PreparedStatement<br>
W większo?ci dokumentów opisuj?cych dobre praktyki w aplikacjach wykorzystuj?cych bazy danych
widzimy podpowiedĽ "używaj klas PreparedStatement". W przypadku zwykłej klasy Statement za każdym
razem, kiedy chcemy wykonać dane polecenie SQL, przed jego wykonaniem następuje parsowanie oraz
sprawdzenie poprawno?ci składni zapytania. W przypadku klasy PreparedStatement wygl?da to
zupełnie inaczej. W pierwszej fazie tworzymy obiekt PreparedStatement, który jako parametr
przyjmuje zapytanie SQL, w którym zamiast istotnych dynamicznych parametrów zapytania podajemy
znak '?'.<br><br>
<font class='code'>
PreparedStatement myPreparedStmt=<br>
conn.prepareStatement("select position, name from tab1 where id=? and code=?");<br>
</font><br>
W ten sposób stworzyli?my zapytanie, które tylko jeden raz będzie sparsowane w celu zbadania
poprawno?ci zapytania. Każde wykonanie zapytania na bazie danych będzie polegało na przekazaniu
do obiektu typu PreparedStatement parametrów zapytania oraz wykonania takie go zapytania bez
powtarzania operacji parsowania i weryfikacji poprawno?ci oraz do pobrania odpowiedzi
bazy danych.<br><br>
<font class='code'>
...<br>
myPreparedStmt.setInt(1, id);<br>
myPreparedStmt.setString(2, code);<br>
ResultSet rs = myPreparedStmt.executeQuery();<br>
while (rs.next()) {<br>
position = rs.getLong(1);<br>
name = rs.getString(2);<br>
...<br>
}<br>
</font>
Warto tu zauważyć, iż do przekazania parametrów zapytania używamy odpowiednich metod setXXX klasy
PreparedStatement, do operacji pobrania informacji z bazy danych metod getXXX klasy ResultSet, gdzie
XXX okre?la jaki typ obiektów przekazujemy jako parametr lub pobieramy z bazy danych.<br><br>
Operacje wsadowe<br>
Aby omówić termin operacje wsadowe podzielę go na dwa w zasadzie oddzielne czę?ci, operacje
wsadowe przy czytaniu oraz operacje wsadowe przy zmianach.
<br><br>
Operacje wsadowe przy czytaniu<br>
Kiedy wysyłamy zapytanie do bazy danych zwracaj?ce wiersze baza do sterownika JDBC nie zwraca
od razy wszystkie wiersze, tylko tak? ilo?ć wierszy, jak? ustawimy w odpowiednim parametrze
sterownika JDBC, klasy Statement lub ResultSet okre?laj?cym wielko?ć bufora rekordów zwracanych
w jednej paczce wysyłanej od bazy do klienta. Nazwa tego parametru zależy od odpowiedniego
sterownika JDBC. Za przykład opisania zasada działania sterownika w przypadku przyjmijmy
zapytanie SQL zwracaj?ce 1000 rekordów oraz bufor rekordów ustawiony na 50. W takim przypadku
pierwsza odpowiedz z bazy będzie zawierała pierwsze 50 rekordów odpowiedzi dopóki będziemy
operowali tylko na tych pierwszych 50 rekordach. Je?li odwołamy się do 51 rekordu (rekord
spoza bież?cej paczki) sterownik wy?le ż?danie do bazy danych ż?danie przesłanie kolejnej
paczki zawieraj?cej rekordy od 51 do 100. Analogicznie będzie to wygl?dało przy kolejnych
rekordach aż do osi?gnięcie końca rekordów z odpowiedzi. Widzimy tu, żę przy takiej konfiguracji
jak tu przedstawionej odczytanie z bazy wszystkich rekordów odpowiedzi wymaga wysłania do
bazy 20 ż?dań (1000/50). Operacje wysyłaj?ce te wewnętrzne ż?dania kolejnych bloków odpowiedzi do
bazy dla programisty s? przeĽroczyste. Ważne jest, aby mieć na uwadze fakt istnienia tego
parametru oraz zasady pobierania odpowiedzi z bazy danych. W naszym przypadku zmieniaj?c
warto?ć bufora rekordów na 512 takich zmniejszymy ilo?ć takich wewnętrznych ż?dań do bazy do 2.
Należy wzi?ć pod uwagę, że wielko?ci tego bufora nie można zwiększać do woli. Musimy tu znaleĽć
złoty ?rodek pomiędzy ilo?ci? operacji sieciowych, a ilo?ci? pamięci wykorzystywanej do
buforowania bloku zwracanych rekordów.<br><br>
Aby ustawić wielko?ć bufora rekordów zwracanych podczas ł?czenia się z baz? danych np. w
przypadku bazy danych Oracle może mieć postać:<br><br>
<font class='code'>
Properties props= new Properties();<br>
props.put("defaultRowPrefetch",256);<br>
</font><br>
W przypadku ustawienia tego parametru za pomoc? klasy Statement lub ResultSet operacja ta ma postać:<br><br>
<font class='code'>
Statement.setFetchSize(int size);<br>
ResultSet.setFetchSize(int size);<br>
</font><br>
Operacje wsadowe przy zmianach<br>
Standardowo wysyłaj?c kilka zmieniaj?cych instrukcji SQL do bazy danych jedna instrukcja to jedno
odwołanie się do bazy danych. Przy operacjach wsadowych przy zmianach celem zwiększenie wydajno?ci
aplikacji instrukcje te wysyłamy za pomoc? jednego odwołania się do bazy danych.<br><br>
Przykład takich operacji wsadowych może mieć postać:<br><br>
<font class='code'>
...<br>
con.setAutoCommit(false);<br>
Statement stm= con.createStatement();<br>
stm.addBatch("INSERT INTO TAB1 VALUES('Jan','Nowak',6)");<br>
stm.addBatch("INSERT INTO TAB1 VALUES('Adam','Kowalski',12)");<br>
stm.addBatch("INSERT INTO TAB1 VALUES('Jacek','Szczepański',15)");<br>
int[] ret=stm.executeBatch();<br>
...<br>
con.commit();<br>
</font><br>
Te same operacje używaj?c klasę PreparedStatement:<br><br>
<font class='code'>
...<br>
con.setAutoCommit(false);<br>
PreparedStatement pstm= con.prepareStatement("INSERT INTO TAB1 VALUES(?,?,?)");<br>
pstm.setString(1,"Jan");<br>
pstm.setString(2,"Nowak");<br>
pstm.setInt(3,6);<br>
pstm.addBatch();<br>
pstm.setString(1,"Adam");<br>
pstm.setString(2,"Kowalski");<br>
pstm.setInt(3,12);<br>
pstm.addBatch();<br>
pstm.setString(1,"Jacek");<br>
pstm.setString(2,"Szczepański");<br>
pstm.setInt(3,15);<br>
pstm.addBatch();<br>
int[] ret=pstm.executeBatch();<br>
...<br>
con.commit();<br>
</font><br>
Minimalizacja ilo?ci zwracanych danych<br>
Podczas projektowania zapytań SQL należy zwrócić uwagę na to aby pobierać z bazy tylko te informacje,
które potem w aplikacji będziemy wykorzystywać. I tak je?li w tabeli tab1 znajduje się 10 kolumn, a my
w aplikacji zamierzamy wykorzystywać tylko dwie kolumny zapytanie<br><br>
<font class='code'>select * from tab1</font><br><br>
wydaje się być zdecydowanie nadmiarowe. Zaleca się w takiej sytuacji użycie zapytania precyzuj?cego
zwracane dane:<br><br>
<font class='code'>select col1,col2 from tab1</font>
<br><br>
Dla niektórych wydaje się to może mało istotne jednak w przypadku, kiedy zwracana jest do?c duża
liczba rekordów polepszenie wydajno?ci spowodowane zmniejszeniem ilo?ci zwracanych danych
będzie z pewno?ci? zauważalne.<br><br>
Sterowniki JDBC<br>
Powrót