Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00661 009443 7438124 na godz. na dobę w sumie
Java Persistence. Programowanie aplikacji bazodanowych w Hibernate. Wydanie II - ebook/pdf
Java Persistence. Programowanie aplikacji bazodanowych w Hibernate. Wydanie II - ebook/pdf
Autor: , , Liczba stron: 640
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-2783-2 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> java - programowanie
Porównaj ceny (książka, ebook (-30%), audiobook).
Utrwalenie danych, tak aby zostały one zapisane i przechowane przez system informatyczny, jest jedną z podstawowych funkcji aplikacji. Prawie zawsze wymaga się trwałych danych. W przypadku Javy zazwyczaj utrwalenie danych odbywa się poprzez ich zapisanie w relacyjnej bazie danych z wykorzystaniem języka SQL. Relacyjne bazy danych stanowią niezwykle elastyczne i potężne narzędzie do zarządzania utrwalonymi danymi, jednak aby wykorzystać wszystkie zalety tego rozwiązania, trzeba zapewnić optymalne komunikowanie się aplikacji z bazą danych.

Niniejsza książka stanowi wyczerpujące źródło aktualnej wiedzy o frameworku Hibernate, najpopularniejszym narzędziu do utrwalania danych dla Javy, które zapewnia automatyczne i przezroczyste mapowanie obiektowo-relacyjne. Wyczerpująco opisano też standard Java Persistence 2.1 (JSR 338). Programowanie aplikacji w Hibernate wyjaśniono tu na licznych przykładach. Pokazano, jak korzystać z mapowania, zapytań, strategii pobierania, transakcji, konwersacji, buforowania i wielu innych funkcji. Nie zabrakło opisu najlepszych praktyk w projektowaniu baz danych oraz wskazówek dotyczących optymalizacji. Wszystkie przykłady zostały uaktualnione dla najnowszych wersji frameworka Hibernate i środowiska Java EE.

Najważniejsze zagadnienia omówione w książce:

Hibernate i Java Persistence — najlepszy sposób na nowoczesną aplikację bazodanową!


Christian Bauer jest szkoleniowcem i konsultantem. Bierze udział w rozwijaniu frameworka Hibernate. Autor kilku książek dotyczących programowania w Javie. Gavin King jest współzałożycielem projektu Hibernate oraz członkiem grupy ekspertów pracujących nad standardem Java Persistence (JSR 220). Przewodził również pracom nad standaryzacją CDI (JSR 299). Gary Gregory jest współautorem książek JUnit in Action oraz Spring Batch in Action. Jest także członkiem grup zarządzania projektami firmy Apache Software Foundation: Commons, HttpComponents, Logging Services i Xalan.
Znajdź podobne książki

Darmowy fragment publikacji:

Tytuł oryginału: Java Persistence with Hibernate, 2nd Edition Tłumaczenie: Radosław Meryk Projekt okładki: Studio Gravite / Olsztyn; Obarek, Pokoński, Pazdrijowski, Zaprucki Materiały graficzne na okładce zostały wykorzystane za zgodą Shutterstock Images LLC. ISBN: 978-83-283-2782-5 Original edition copyright © 2016 by Manning Publications Co. All rights reserved. Polish edition copyright © 2017 by HELION SA All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/javpe2 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treści Słowo wstępne do pierwszego wydania 17 Przedmowa 19 Podziękowania 21 O książce 23 O autorach 27 CZĘŚĆ I WPROWADZENIE W TEMATYKĘ ORM 29 Rozdział 1. Utrwalanie obiektowo-relacyjne 31 1.1. Co to jest utrwalanie? 32 1.1.1. Relacyjne bazy danych 33 1.1.2. 1.1.3. Korzystanie z języka SQL w Javie 35 Język SQL 34 1.2. Niedopasowanie paradygmatów 37 1.2.1. 1.2.2. 1.2.3. 1.2.4. 1.2.5. Problem ziarnistości 38 Problem podtypów 40 Problem tożsamości 41 Problemy związane z asocjacjami 43 Problem poruszania się po danych 44 1.3. ORM i JPA 45 1.4. Podsumowanie 47 Rozdział 2. Zaczynamy projekt 49 2.1. Wprowadzenie do frameworka Hibernate 49 2.2. Aplikacja „Witaj, świecie” z JPA 50 2.2.1. Konfigurowanie jednostki utrwalania 51 2.2.2. 2.2.3. Pisanie klasy utrwalania 53 Zapisywanie i ładowanie komunikatów 54 2.3. Natywne mechanizmy konfiguracji frameworka Hibernate 57 2.4. Podsumowanie 60 3.1. Rozdział 3. Modele dziedziny i metadane 61 Przykładowa aplikacja CaveatEmptor 62 3.1.1. Architektura warstwowa 62 3.1.2. Analiza dziedziny biznesowej 64 3.1.3. Model dziedziny aplikacji CaveatEmptor 65 Poleć książkęKup książkę 8 Spis treści 3.2. Implementacja modelu dziedziny 66 3.2.1. Rozwiązanie problemu wyciekania obszarów zainteresowania 67 3.2.2. 3.2.3. 3.2.4. Przezroczyste i zautomatyzowane utrwalanie 68 Pisanie klas zdolnych do utrwalania 69 Implementacja asocjacji POJO 73 3.3. Metadane modelu dziedziny 77 3.3.1. Metadane bazujące na adnotacjach 78 Stosowanie reguł Bean Validation 80 3.3.2. 3.3.3. Pobieranie metadanych z zewnętrznych plików XML 83 3.3.4. Dostęp do metadanych w fazie działania aplikacji 87 Podsumowanie 90 3.4. CZĘŚĆ II STRATEGIE MAPOWANIA 91 Rozdział 4. Mapowanie klas utrwalania 93 4.1. Encje i typy wartości 93 4.1.1. Drobnoziarniste modele dziedziny 94 4.1.2. Definiowanie pojęć aplikacji 94 4.1.3. Odróżnianie encji od typów wartości 96 4.2. Mapowanie encji z tożsamością 97 Tożsamość a równość w Javie 98 Pierwsza klasa encji i mapowanie 98 4.2.1. 4.2.2. 4.2.3. Wybieranie klucza głównego 100 4.2.4. Konfigurowanie generatorów kluczy 101 4.2.5. Strategie generatorów identyfikatorów 104 4.3. Opcje mapowania encji 108 Zarządzanie nazwami 108 4.3.1. 4.3.2. Dynamiczne generowanie SQL 111 4.3.3. Encje niezmienne 112 4.3.4. Mapowanie encji na podzapytanie 113 Podsumowanie 114 4.4. Rozdział 5. Mapowanie typów wartości 117 5.1. Mapowanie prostych właściwości 118 Przesłanianie domyślnego zachowania dla właściwości o typach prostych 119 Personalizacja dostępu do właściwości 120 5.1.1. 5.1.2. 5.1.3. Używanie właściwości wyprowadzonych 122 5.1.4. 5.1.5. Wygenerowane i domyślne wartości właściwości 124 5.1.6. Właściwości opisujące czas 125 5.1.7. Mapowanie typów wyliczeniowych 126 Transformacje wartości kolumn 123 5.2. Mapowanie komponentów osadzanych 126 Schemat bazy danych 127 Przystosowanie klas do osadzania 127 Przesłanianie osadzonych atrybutów 131 5.2.1. 5.2.2. 5.2.3. 5.2.4. Mapowanie zagnieżdżonych komponentów osadzanych 132 Poleć książkęKup książkę Spis treści 9 5.3. Mapowanie typów Java i SQL za pomocą konwerterów 134 Typy wbudowane 134 Tworzenie własnych konwerterów JPA 140 5.3.1. 5.3.2. 5.3.3. Rozszerzanie frameworka Hibernate za pomocą typów użytkownika 147 Podsumowanie 154 5.4. Rozdział 6. Mapowanie dla dziedziczenia 155 Jedna tabela na konkretną klasę. Niejawna obsługa polimorfizmu 156 Jedna tabela na konkretną klasę oraz unie 158 Jedna tabela na hierarchię klas 160 Jedna tabela na podklasę oraz złączenia 164 6.1. 6.2. 6.3. 6.4. 6.5. Mieszane strategie dziedziczenia 167 6.6. Dziedziczenie klas osadzanych 169 6.7. Wybór strategii 172 6.8. Asocjacje polimorficzne 173 Polimorficzne asocjacje wiele-do-jednego 173 Polimorficzne kolekcje 176 6.8.1. 6.8.2. Podsumowanie 177 6.9. Rozdział 7. Mapowanie kolekcji i asocjacje pomiędzy encjami 179 7.1. Schemat bazy danych 180 Tworzenie i mapowanie właściwości będących kolekcjami 180 Zbiory, kolekcje bag, listy i mapy typów wartości 180 7.1.1. 7.1.2. 7.1.3. Wybór interfejsu kolekcji 182 7.1.4. Mapowanie zbioru 184 7.1.5. Mapowanie kolekcji bag identyfikatorów 185 7.1.6. Mapowanie list 186 7.1.7. Mapowanie mapy 187 7.1.8. Kolekcje posortowane i uporządkowane 188 7.2. Kolekcje komponentów 191 7.2.1. Równość egzemplarzy komponentu 192 7.2.2. Kolekcja Set komponentów 194 7.2.3. Kolekcja bag komponentów 196 7.2.4. Mapa wartości komponentów 197 7.2.5. Komponenty jako klucze mapy 198 7.2.6. Kolekcje w komponencie osadzanym 199 7.3. Mapowanie asocjacji encji 200 7.3.1. Najprostsza możliwa asocjacja 201 7.3.2. Definiowanie asocjacji dwukierunkowych 202 7.3.3. Kaskadowe zmiany stanu 204 Podsumowanie 211 7.4. Poleć książkęKup książkę 10 Spis treści Rozdział 8. Zaawansowane mapowanie asocjacji pomiędzy encjami 213 8.1. Asocjacje jeden-do-jednego 214 8.1.1. Współdzielenie klucza głównego 214 8.1.2. Generator kluczy obcych i głównych 217 8.1.3. Wykorzystanie kolumny złączenia klucza obcego 220 8.1.4. Korzystanie z tabeli złączenia 221 8.2. Asocjacje jeden-do-wielu 224 Jednokierunkowe i dwukierunkowe mapowania list 226 8.2.1. Kolekcje bag jeden-do-wielu 224 8.2.2. 8.2.3. Opcjonalna asocjacja jeden-do-wielu z tabelą złączenia 228 8.2.4. Asocjacje jeden-do-wielu w klasach osadzanych 230 8.3. Asocjacje wiele-do-wielu i asocjacje potrójne 232 Jednokierunkowe i dwukierunkowe asocjacje wiele-do-wielu 232 8.3.1. 8.3.2. Asocjacja wiele-do-wielu z pośrednią encją 234 8.3.3. Asocjacje trójelementowe z komponentami 238 8.4. Asocjacje pomiędzy encjami z wykorzystaniem kolekcji Map 241 8.4.1. Relacje jeden-do-wielu z kluczem w postaci właściwości 241 8.4.2. Relacje trójczłonowe klucz-wartość 243 Podsumowanie 244 8.5. Rozdział 9. Schematy złożone i odziedziczone 245 9.1. Ulepszanie schematu bazy danych 246 9.1.1. Dodawanie pomocniczych obiektów bazy danych 247 9.1.2. Ograniczenia SQL 250 9.1.3. Tworzenie indeksów 257 9.2. Obsługa kluczy odziedziczonych 258 9.2.1. Mapowanie naturalnych kluczy głównych 258 9.2.2. Mapowanie złożonych kluczy głównych 259 9.2.3. Klucze obce w złożonych kluczach głównych 261 9.2.4. Klucze obce odwołująe się do złożonych kluczy głównych 264 9.2.5. Klucze obce odwołujące się do pól niebędących kluczami głównymi 265 9.3. Mapowanie właściwości do tabel pomocniczych 266 9.4. Podsumowanie 268 CZĘŚĆ III TRANSAKCYJNE PRZETWARZANIE DANYCH 269 Rozdział 10. Zarządzanie danymi 271 10.1. Cykl życia utrwalania 272 10.1.1. Stany egzemplarza encji 273 10.1.2. Kontekst utrwalania 274 10.2. Interfejs EntityManager 276 10.2.1. Kanoniczna jednostka pracy 276 10.2.2. Utrwalanie danych 278 10.2.3. Pobieranie i modyfikowanie trwałych danych 279 10.2.4. Pobieranie referencji 281 10.2.5. Przełączanie danych do stanu przejściowego 282 10.2.6. Odświeżanie danych 284 Poleć książkęKup książkę Spis treści 11 10.2.7. Replikowanie danych 284 10.2.8. Buforowanie w kontekście utrwalania 285 10.2.9. Synchronizowanie kontekstu utrwalania 287 10.3. Praca z encjami w stanie odłączonym 288 Implementacja metody równości 291 10.3.1. Tożsamość odłączonych egzemplarzy 289 10.3.2. 10.3.3. Odłączanie egzemplarzy encji 294 10.3.4. Scalanie egzemplarzy encji 295 10.4. Podsumowanie 297 Rozdział 11. Transakcje i współbieżność 299 11.1. Podstawowe wiadomości o transakcjach 300 11.1.1. Cechy ACID 300 11.1.2. Transakcje bazodanowe i systemowe 301 11.1.3. Transakcje programowe z JTA 301 11.1.4. Obsługa wyjątków 303 11.1.5. Deklaratywne rozgraniczanie transakcji 306 11.2. Zarządzanie współbieżnym dostępem 306 11.2.1. Współbieżność na poziomie bazy danych 307 11.2.2. Optymistyczne zarządzanie współbieżnością 312 11.2.3. 11.2.4. Unikanie zakleszczeń 324 Jawne pesymistyczne blokady 320 11.3. Dostęp do danych na zewnątrz transakcji 325 11.3.1. Czytanie danych w trybie autozatwierdzania 326 11.3.2. Kolejkowanie modyfikacji 328 11.4. Podsumowanie 329 Rozdział 12. Plany pobierania, strategie i profile 331 12.1. Ładowanie leniwe i zachłanne 332 12.1.1. Obiekty proxy encji 333 12.1.2. Leniwe ładowanie trwałych kolekcji 337 12.1.3. Leniwe ładowanie z przechwytywaniem 339 12.1.4. Zachłanne ładowanie asocjacji i kolekcji 342 12.2. Wybór strategii pobierania 344 12.2.1. Problem n+1 instrukcji SELECT 345 12.2.2. Problem iloczynu kartezjańskiego 346 12.2.3. Pobieranie danych partiami z wyprzedzeniem 349 12.2.4. Pobieranie kolekcji z wyprzedzeniem z wykorzystaniem podzapytań 351 12.2.5. Pobieranie zachłanne z wieloma instrukcjami SELECT 352 12.2.6. Dynamiczne pobieranie zachłanne 353 12.3. Korzystanie z profili pobierania 355 12.3.1. Deklarowanie profili pobierania Hibernate 356 12.3.2. Korzystanie z grafów encji 357 12.4. Podsumowanie 361 Poleć książkęKup książkę 12 Spis treści Rozdział 13. Filtrowanie danych 363 13.1. Kaskadowe przejścia stanu 364 13.1.1. Dostępne opcje kaskadowe 365 13.1.2. Przechodnie odłączanie i scalanie 366 13.1.3. Kaskadowe odświeżanie 368 13.1.4. Kaskadowe replikacje 370 13.1.5. Włączanie globalnej opcji przechodniego utrwalania 371 13.2. Nasłuchiwanie i przechwytywanie zdarzeń 372 13.2.1. Obserwatory zdarzeń i wywołania zwrotne JPA 372 13.2.2. 13.2.3. Rdzeń systemu obsługi zdarzeń 380 Implementacja interceptorów Hibernate 376 13.3. Audyt i wersjonowanie z wykorzystaniem Hibernate Envers 382 13.3.1. Aktywacja rejestrowania audytu 382 13.3.2. Tworzenie śladu audytu 384 13.3.3. Szukanie wersji 385 13.3.4. Dostęp do historycznych danych 386 13.4. Dynamiczne filtry danych 389 13.4.1. Definiowanie dynamicznych filtrów 390 13.4.2. Stosowanie filtra 390 13.4.3. Włączanie filtra 391 13.4.4. Filtrowanie dostępu do kolekcji 392 13.5. Podsumowanie 393 CZĘŚĆ IV PISANIE ZAPYTAŃ 395 Rozdział 14. Tworzenie i uruchamianie zapytań 397 14.1. Tworzenie zapytań 398 Interfejsy zapytań JPA 398 14.1.1. 14.1.2. Wyniki zapytania z określonym typem danych 401 14.1.3. Interfejsy zapytań frameworka Hibernate 402 14.2. Przygotowywanie zapytań 403 14.2.1. Zabezpieczenie przed atakami wstrzykiwania SQL 403 14.2.2. Wiązanie parametrów nazwanych 404 14.2.3. Korzystanie z parametrów pozycyjnych 406 14.2.4. Stronicowanie dużych zbiorów wyników 406 14.3. Uruchamianie zapytań 408 14.3.1. Wyszczególnianie wszystkich wyników 408 14.3.2. Pobieranie pojedynczego wyniku 408 14.3.3. Przewijanie z wykorzystaniem kursorów bazy danych 409 14.3.4. Iterowanie po wynikach 411 14.4. Nazywanie i eksternalizacja zapytań 412 14.4.1. Wywoływanie zapytania przez nazwę 412 14.4.2. Definiowanie zapytań w metadanych XML 413 14.4.3. Definiowanie zapytań z adnotacjami 414 14.4.4. Programowe definiowanie nazwanych zapytań 415 14.5. Podpowiedzi do zapytań 416 14.5.1. Ustawianie limitu czasu 417 14.5.2. Ustawianie trybu synchronizacji 417 Poleć książkęKup książkę Spis treści 13 14.5.3. Ustawianie trybu tylko do odczytu 418 14.5.4. Ustawianie rozmiaru pobierania 418 14.5.5. Ustawianie komentarza SQL 419 14.5.6. Podpowiedzi nazwanych zapytań 419 14.6. Podsumowanie 421 Rozdział 15. Języki zapytań 423 15.1. Selekcja 424 15.1.1. Przypisywanie aliasów i rdzeni zapytań 425 15.1.2. Zapytania polimorficzne 426 15.2. Ograniczenia 427 15.2.1. Wyrażenia porównań 428 15.2.2. Wyrażenia z kolekcjami 432 15.2.3. Wywoływanie funkcji 433 15.2.4. Sortowanie wyników zapytania 436 15.3. Rzutowanie 437 15.3.1. Rzutowanie encji i wartości skalarnych 437 15.3.2. Dynamiczne tworzenie egzemplarzy 439 15.3.3. Niepowtarzalność wyników 440 15.3.4. Wywoływanie funkcji w projekcjach 441 15.3.5. Funkcje agregacji 443 15.3.6. Grupowanie 445 15.4. Złączenia 446 15.4.1. Złączenia w SQL 447 15.4.2. Opcje złączenia w JPA 449 15.4.3. Niejawne złączenia asocjacyjne 449 15.4.4. Złączenia jawne 451 15.4.5. Dynamiczne pobieranie ze złączeniami 453 15.4.6. Złączenia teta 456 15.4.7. Porównywanie identyfikatorów 457 15.5. Podzapytania 459 15.5.1. Zagnieżdżanie skorelowane i nieskorelowane 460 15.5.2. Kwantyfikacja 461 15.6. Podsumowanie 462 Rozdział 16. Zaawansowane opcje zapytań 465 16.1. Transformacje wyników zapytań 466 16.1.1. Zwracanie listy list 466 16.1.2. Zwracanie listy map 467 16.1.3. Mapowanie aliasów na właściwości JavaBean 468 16.1.4. Pisanie własnej implementacji klasy ResultTransformer 469 16.2. Filtrowanie kolekcji 470 16.3. API Criteria frameworka Hibernate 473 16.3.1. Selekcja i porządkowanie 473 16.3.2. Ograniczanie 474 16.3.3. Rzutowanie i agregacja 475 Poleć książkęKup książkę 14 Spis treści 16.3.4. Złączenia 477 16.3.5. Podzapytania 478 16.3.6. Zapytania przez przykład 479 16.4. Podsumowanie 482 Rozdział 17. Dostosowywanie SQL 483 17.1. Korzystanie z trybu JDBC 484 17.2. Mapowanie wyników zapytania SQL 486 17.2.1. Rzutowanie z zapytaniami SQL 487 17.2.2. Mapowanie na klasy encji 488 17.2.3. Dostosowywanie mapowania wyników 490 17.2.4. Eksternalizacja natywnych zapytań 502 17.3. Dostosowywanie operacji CRUD 505 17.3.1. Własne mechanizmy ładujące 505 17.3.2. Personalizacja operacji tworzenia, aktualizowania i usuwania egzemplarzy encji 507 17.3.3. Personalizacja operacji na kolekcjach 509 17.3.4. Zachłanne pobieranie we własnych mechanizmach ładujących 511 17.4. Wywoływanie procedur składowanych 513 17.4.1. Zwracanie zbioru wyników 515 17.4.2. Zwracanie wielu zbiorów wyników oraz liczników aktualizacji 516 17.4.3. Ustawianie parametrów wejściowych i wyjściowych 518 17.4.4. Zwracanie kursora 521 17.5. Wykorzystywanie procedur składowanych do operacji CRUD 522 17.5.1. Spersonalizowany mechanizm ładujący z procedurą 523 17.5.2. Procedury dla operacji CUD 524 17.6. Podsumowanie 526 CZĘŚĆ V BUDOWANIE APLIKACJI 527 Rozdział 18. Projektowanie aplikacji klient-serwer 529 18.1. Tworzenie warstwy utrwalania 530 18.1.1. Generyczny wzorzec obiektu dostępu do danych 532 18.1.2. 18.1.3. 18.1.4. Testowanie warstwy utrwalania 538 Implementacja generycznego interfejsu 533 Implementacja obiektów DAO encji 536 18.2. Budowa serwera bezstanowego 540 18.2.1. Edycja przedmiotu aukcji 540 18.2.2. Składanie oferty 543 18.2.3. Analiza aplikacji bezstanowej 546 18.3. Budowanie serwera stateful 548 18.3.1. Edycja przedmiotu aukcji 549 18.3.2. Analiza aplikacji stateful 554 18.4. Podsumowanie 556 Poleć książkęKup książkę Spis treści 15 Rozdział 19. Budowanie aplikacji webowych 557 19.1. Integracja JPA z CDI 558 19.1.1. Tworzenie obiektu EntityManager 558 19.1.2. Łączenie obiektu EntityManager z transakcjami 560 19.1.3. Wstrzykiwanie obiektu EntityManager 560 19.2. Stronicowanie i sortowanie danych 562 19.2.1. Stronicowanie na bazie przesunięć a stronicowanie przez przeszukiwanie 563 19.2.2. Stronicowanie w warstwie utrwalania 565 19.2.3. Odpytywanie strona po stronie 571 19.3. Budowanie aplikacji JSF 572 19.3.1. Usługi o zasięgu żądania 572 19.3.2. Usługi o zasięgu konwersacji 576 19.4. Serializacja danych modelu dziedziny 585 19.4.1. Pisanie usługi JAX-RS 585 19.4.2. Stosowanie mapowań JAXB 587 19.4.3. Serializacja obiektów proxy frameworka Hibernate 589 19.5. Podsumowanie 593 Rozdział 20. Skalowanie Hibernate 595 20.1. Przetwarzanie masowe i wsadowe 596 Instrukcje masowe w JPQL i API kryteriów 596 20.1.1. 20.1.2. Masowe instrukcje w SQL 601 20.1.3. Przetwarzanie wsadowe 602 20.1.4. Interfejs StatelessSession frameworka Hibernate 606 20.2. Buforowanie danych 608 20.2.1. Architektura współdzielonej pamięci podręcznej frameworka Hibernate 609 20.2.2. Konfigurowanie współdzielonej pamięci podręcznej 614 20.2.3. Buforowanie encji i kolekcji 616 20.2.4. Testowanie współdzielonej pamięci podręcznej 619 20.2.5. Ustawianie trybów pamięci podręcznej 622 20.2.6. Zarządzanie współdzieloną pamięcią podręczną 623 20.2.7. Pamięć podręczna wyników zapytania 624 20.3. Podsumowanie 627 Bibliografia 629 Skorowidz 631 Poleć książkęKup książkę 16 Spis treści Poleć książkęKup książkę Mapowanie klas utrwalania W tym rozdziale:  omówienie encji i typów wartości;  mapowanie klas encji z tożsamością;  zarządzanie opcjami mapowania na poziomie encji. W tym rozdziale zaprezentujemy podstawowe opcje mapowania i wyjaśnimy sposób mapowania klas encji na tabele SQL. Pokażemy i omówimy sposoby obsługi identyfi- katorów baz danych i kluczy głównych oraz użycia różnych innych ustawień metadanych pozwalających na spersonalizowanie tego, jak framework Hibernate ładuje i magazynuje egzemplarze klas modelu dziedziny. We wszystkich przykładach mapowania wykorzy- stamy adnotacje JPA. Najpierw jednak zdefiniujemy podstawowe rozgraniczenie pomię- dzy encjami a typami wartości i wyjaśnimy, w jaki sposób powinniśmy podejść do mapowania obiektowo-relacyjnego modelu dziedziny. Najważniejsza nowa własność w JPA 2 Za pomocą elementu delimited-identifiers w pliku konfiguracyjnym persistence.xml można włączyć globalne „unieszkodliwianie” wszystkich nazw w generowanych instruk- cjach SQL. 4.1. Encje i typy wartości Analizując model dziedziny, można zauważyć różnice pomiędzy klasami: niektóre typy wydają się ważniejsze od innych — reprezentują obiekty biznesowe pierwszej klasy (termin obiekt został tutaj użyty w jego podstawowym znaczeniu). Przykładem są klasy Poleć książkęKup książkę 94 ROZDZIAŁ 4. Mapowanie klas utrwalania Item, Category i User: są to encje świata rzeczywistego, dla których próbujemy stworzyć reprezentacje (wróć do rysunku 3.3, na którym pokazano przykładowy model dzie- dziny). Inne typy występujące w modelu dziedziny, takie jak Address, String i Integer, wydają się mniej ważne. W tym podrozdziale opowiemy, co to znaczy używać drobno- ziarnistych modeli dziedziny oraz w jaki sposób odróżnić encje od typów wartości. 4.1.1. Drobnoziarniste modele dziedziny Głównym celem frameworka Hibernate jest wsparcie dla drobnoziarnistych i bogatych modeli dziedziny. Jest to jeden z powodów, dla których korzystamy z obiektów POJO. W uproszczeniu określenie drobnoziarnisty model oznacza model, w którym jest więcej klas niż tabel. Na przykład użytkownik w modelu dziedziny może mieć adres domowy. W bazie danych może występować pojedyncza tabela USERS z kolumnami HOME_STREET, HOME_CITY i HOME_ZIPCODE (pamiętasz problem typów SQL, który omawialiśmy w punkcie 1.2.1?). W modelu dziedziny moglibyśmy użyć tego samego podejścia — zaprezentować adres w postaci trzech właściwości tekstowych klasy User. Jednak znacznie lepsze jest zamodelowanie adresu z wykorzystaniem klasy Address, gdzie w klasie User występuje właściwość homeAddress. Taki model dziedziny gwarantuje ulepszoną spójność i łatwiej- sze ponowne użycie kodu. Ponadto jest bardziej zrozumiały niż SQL z nieelastycznymi systemami typów. Specyfikacja JPA podkreśla przydatność drobnoziarnistych klas do implementacji bezpieczeństwa typów i zachowań. Wiele osób na przykład modeluje adres e-mail jako tekstową właściwość klasy User. Bardziej zaawansowanym podejściem jest zdefiniowa- nie klasy EmailAddress, która dodaje bardziej wysokopoziomową semantykę i zacho- wanie — klasa ta może dostarczać metodę prepareMail(), jednak nie powinna zawierać metody sendMail(), ponieważ nie chcemy, aby klasy modelu dziedziny zależały od podsystemu pocztowego. Problem ziarnistości prowadzi do rozróżnienia pomiędzy klasami, które w kontekście mechanizmów ORM ma centralne znaczenie. W Javie wszystkie klasy są równe — wszystkie egzemplarze mają własny identyfikator i cykl życia. Gdy wprowadzimy utrwa- lanie, to może się zdarzyć, że niektóre egzemplarze nie będą mieć własnych identyfi- katorów i cyklu życia, lecz będą zależeć od innych. Spróbujmy przeanalizować przykład. 4.1.2. Definiowanie pojęć aplikacji Dwie osoby mieszkają w tym samym domu i obie mają zarejestrowane konta użyt- kownika systemu CaveatEmptor. Niechaj będą to Jan i Janina. Każde konto reprezentuje egzemplarz klasy User. Ponieważ chcemy ładować, zapi- sywać i usuwać egzemplarze klasy User niezależnie do siebie, to User jest klasą encji, a nie typem wartości. Wyszukiwanie klas encji jest łatwe. Klasa User ma właściwość homeAddress. Jest to asocjacja z klasą Address. Czy oba egzemplarze klasy User mają w fazie działania aplikacji referencje do tego samego egzem- plarza klasy Address, czy też każdy egzemplarz klasy User ma referencję do własnego egzemplarza klasy Address? Czy ma znaczenie to, że Jan i Janina mieszkają w tym samym domu? Poleć książkęKup książkę 4.1. Encje i typy wartości 95 Na rysunku 4.1 pokazano sytuację, w której dwa egzemplarze klasy User współdzielą egzemplarz klasy Address (to jest diagram obiektów UML, a nie diagram klas). Jeżeli obiekt klasy Address ma wspierać współdzielenie referencji w fazie działania, to jest to typ encji. Egzemplarz klasy Address ma własny cykl życia. Nie można go usunąć, gdy Jan usunie swoje konto User. Janina w dalszym ciągu będzie korzystać z referencji do tego egzemplarza klasy Address. Rysunek 4.1. Dwa egzemplarze klasy User mają referencje do jednego egzemplarza klasy Address Przyjrzyjmy się teraz modelowi alternatywnemu, w którym każdy obiekt klasy User dysponuje referencją do własnego egzemplarza homeAddress — tak jak pokazano na rysunku 4.2. W tym przypadku można uzależnić egzemplarz klasy Address od egzemplarza klasy User: zdefiniujemy go jako typ wartości. Gdy Jan usunie swoje konto User, można bezpiecznie usunąć związany z nim egzemplarz klasy Address. Ta referencja nie będzie występować w egzemplarzu żadnej innej klasy. Rysunek 4.2. Dwa egzemplarze klasy User, z których każdy ma własny, zależny egzemplarz klasy Address Wprowadzamy zatem następujące, zasadnicze rozróżnienie:  Możemy pobrać egzemplarz typu encji, używając jego tożsamości utrwalania: na przykład egzemplarza User, Item albo Category. Referencja do egzemplarza encji (wskaźnika w JVM) jest utrwalana jako referencja w bazie danych (wartość z ograniczeniem klucza obcego). Egzemplarz encji ma własny cykl życia. Może istnieć niezależnie od dowolnej innej encji. Wybrane klasy modelu dziedziny mapujemy jako typy encji.  Egzemplarz typu wartości nie ma właściwości identyfikatora utrwalania. Należy do egzemplarza encji. Jego cykl życia jest powiązany z egzemplarzem encji, który jest jego właścicielem. Egzemplarz typu wartości nie wspiera współdzielonych referencji. Najbardziej oczywistymi typami wartości są wszystkie klasy zdefi- niowane w JDK, takie jak String, Integer, a nawet typy proste. Można także mapować jako typy wartości klasy należące do naszego własnego modelu dzie- dziny: na przykład Address i MonetaryAmount. Poleć książkęKup książkę 96 ROZDZIAŁ 4. Mapowanie klas utrwalania W specyfikacji JPA można znaleźć takie samo pojęcie. Jednak typy wartości w specyfi- kacji JPA są nazywane prostymi typami właściwości albo klasami osadzanymi (embed- dable classes). Do tej tematyki powrócimy w następnym rozdziale. Najpierw skoncen- trujemy się na encjach. Identyfikowanie encji i typów wartości w modelu dziedziny nie jest zadaniem reali- zowanym ad hoc, ale lecz zgodnie z konkretną procedurą. 4.1.3. Odróżnianie encji od typów wartości Do diagramów klas UML można dodać informację na temat stereotypu (mechanizm rozszerzeń UML). Dzięki niemu możliwe jest natychmiastowe rozpoznanie encji i typów wartości. Ta praktyka zmusza także, aby myśleć o zastosowaniu tego rozróżnienia dla wszystkich klas. Jest to pierwszy krok na drodze do optymalnego mapowania oraz wydajnie działającej warstwy utrwalania. Przykład zaprezentowano na rysunku 4.3. Rysunek 4.3. Stereotypy dla encji i typów wartości na diagramach UML Klasy Item i User są oczywistymi encjami. Każda ma własną tożsamość, ich egzemplarze zawierają referencje z wielu innych egzemplarzy (referencje współdzielone) i mają niezależne cykle życia. Oznaczenie klasy Address jako typu wartości również jest łatwe: pojedynczy egzem- plarz klasy User odwołuje się do konkretnego egzemplarza klasy Address. Wiemy to, ponieważ asocjację utworzono jako kompozycję, przy czym egzemplarzowi klasy User została powierzona pełna odpowiedzialność za cykl życia egzemplarza klasy Address. Z tego powodu do egzemplarzy klasy Address nie mogą odwoływać się inne obiekty. Egzemplarze te nie potrzebują też własnej tożsamości. Problem może stworzyć klasa Bid. W modelowaniu obiektowym jest ona oznaczana jako kompozycja (asocjacja pomiędzy egzemplarzem klasy Item i Bid oznaczona rombem). Egzemplarz Item jest zatem właścicielem jego egzemplarzy klasy Bid i zawiera zbiór referencji. Na pierwszy rzut oka wydaje się to sensowne, ponieważ oferty w systemie aukcji są bezużyteczne w przypadku, gdy towar, na który zostały złożone, jest niedo- stępny. Co jednak zrobić, jeśli rozszerzenie modelu dziedziny w przyszłości będzie wymagać kolekcji User#bids, zawierającej wszystkie oferty złożone przez konkretnego użytkow- nika? W tym momencie asocjacja pomiędzy egzemplarzami Bid i User jest jednokie- runkowa; egzemplarz klasy Bid zawiera referencję bidder. Co by było, gdyby była ona dwukierunkowa? W tym przypadku bylibyśmy zmuszeni do obsługi możliwego współdzielenia refe- rencji z egzemplarzami klasy Bid, więc klasa Bid musiałaby być encją. Ma zależny cykl życia, ale musiałaby mieć też własną tożsamość w celu wsparcia dla (przyszłych) współdzielonych referencji. Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 97 Z takim mieszanym zachowaniem można się często spotkać. W takiej sytuacji pierw- szą reakcją powinno być przekształcenie wszystkich tego rodzaju klas na typy wartości i promowanie ich do encji tylko wtedy, kiedy to jest absolutnie konieczne. Należy dążyć do upraszczania asocjacji: na przykład utrwalane kolekcje często dodają złożoność bez jakichkolwiek korzyści. Zamiast mapować kolekcje Item#bids i User#bids, możemy napisać zapytania, aby uzyskać wszystkie oferty dla egzemplarza klasy Item oraz te, które złożył określony użytkownik. Asocjacje na diagramie UML będą przebiegały od egzemplarza Bid do egzemplarzy Item i User dokładnie w tym kierunku, a nie w kie- runku przeciwnym. Dla klasy Bid zostanie użyty stereotyp Value type . Do tego tematu wrócimy w rozdziale 7. Następnie na podstawie diagramu modelu dziedziny zaimplementujemy obiekty POJO dla wszystkich encji i typów wartości. Należy zatroszczyć się o trzy rzeczy:  Współdzielone referencje — podczas pisania klas POJO należy unikać współ- dzielenia referencji do egzemplarzy typów wartości. Należy na przykład zadbać o to, aby tylko jeden egzemplarz klasy User mógł odwoływać się do egzemplarza klasy Address. Klasę Address można zaimplementować jako niezmienną, nie definiując publicznej metody setUser() i wymuszając relację za pomocą publicz- nego konstruktora pobierającego argument typu User. Oczywiście — zgodnie z tym, o czym mówiliśmy w poprzednim rozdziale — nadal potrzebujemy kon- struktora bez argumentów (prawdopodobnie protected), tak aby framework Hibernate również mógł tworzyć egzemplarze.  Zależności cyklu życia — jeżeli egzemplarz klasy User zostanie usunięty, jego zależność (egzemplarz klasy Address) także musi zostać usunięta. Metadane utrwa- lania zawierają kaskadowe reguły dla wszystkich takich zależności, więc Hiber- nate (lub baza danych) może zadbać o usunięcie przestarzałych egzemplarzy klasy Address. Należy zaprojektować procedury aplikacji i interfejs użytkownika tak, by respektowały takie zależności i ich oczekiwały — trzeba odpowiednio napisać obiekty POJO modelu dziedziny.  Tożsamość — klasy encji wymagają właściwości identyfikatora w prawie wszyst- kich przypadkach. Klasy typu wartości (i oczywiście klasy JDK takie jak String i Integer) nie mają właściwości identyfikatora, ponieważ egzemplarze są iden- tyfikowane za pośrednictwem encji właściciela. Do referencji, asocjacji i reguł cyklu życia powrócimy przy okazji omawiania bardziej zaawansowanych odwzorowań w dalszych rozdziałach niniejszej książki. Następnym tematem będzie tożsamość i właściwości identyfikatorów. 4.2. Mapowanie encji z tożsamością Mapowanie encji z tożsamością wymaga zrozumienia pojęć tożsamości i równości w Javie. Dopiero po omówieniu tych pojęć przejdziemy do przykładu klasy encji i jej mapowania. W dalszej części rozdziału omówimy bardziej szczegółowe zagadnienia. Opiszemy problemy wybierania klucza podstawowego, konfigurowania generatorów Poleć książkęKup książkę 98 ROZDZIAŁ 4. Mapowanie klas utrwalania kluczy i na koniec przejdziemy do strategii generowania identyfikatorów. Zanim przej- dziemy do omówienia pojęcia tożsamość bazy danych oraz sposobu zarządzania tożsa- mością w specyfikacji JPA, wyjaśnimy różnicę pomiędzy tożsamością a równością obiektów w Javie. 4.2.1. Tożsamość a równość w Javie Deweloperzy Javy rozumieją różnicę między tożsamością a równością obiektów Javy. Tożsamość obiektów (==) to pojęcie zdefiniowane przez maszynę wirtualną Javy. Dwie referencje są identyczne, jeżeli wskazują na tę samą lokalizację w pamięci. Z kolei równość obiektów, czasami nazywana też równoważnością, jest pojęciem zdefiniowanym przez metodę equals() klas. Równoważność oznacza, że dwa różne (nieidentyczne) egzemplarze mają tę samą wartość — ten sam stan. Dwa różne egzem- plarze klasy String są równe, jeżeli reprezentują tę samą sekwencję znaków pomimo tego, że każdy egzemplarz ma własne miejsce w przestrzeni pamięci maszyny wirtualnej (z czytelnikami, którzy są ekspertami w Javie, musimy się zgodzić, że klasa String to przypadek specjalny; załóżmy, że do tego samego stwierdzenia skorzystaliśmy z innej klasy). Utrwalanie komplikuje ten obraz. W przypadku utrwalania obiektowo-relacyjnego egzemplarz utrwalania jest w pamięci reprezentacją konkretnego wiersza (albo wierszy) tabeli (lub tabel) bazy danych. Wraz z tożsamością i równością w Javie zdefiniujemy tożsamość bazy danych. Mamy teraz trzy metody rozróżniania referencji:  Obiekty są identyczne, jeżeli zajmują to samo miejsce w pamięci maszyny JVM. Można to sprawdzić za pomocą operatora a==b. To pojęcie jest znane jako tożsa- mość obiektów.  Obiekty są równe, jeżeli mają ten sam stan zgodnie z definicją w metodzie a.equals(Object b). Klasy, które jawnie nie przesłaniają tej metody, dziedziczą implementację zdefiniowaną w klasie java.lang.Object, która porównuje toż- samość obiektów za pomocą operatora ==. To pojęcie jest znane jako równość obiektów.  Obiekty zapisane w relacyjnej bazie danych są identyczne, jeżeli współdzielą tę samą tabelę i wartość klucza głównego. To pojęcie, zmapowane do przestrzeni Javy, jest znane jako tożsamość bazy danych. Przyjrzyjmy się teraz, w jaki sposób tożsamość na poziomie bazy danych łączy się z toż- samością obiektów oraz w jaki sposób można wyrazić tożsamość bazy danych w meta- danych mapowania. W ramach przykładu stworzymy mapę encji należącej do modelu dziedziny. 4.2.2. Pierwsza klasa encji i mapowanie W poprzednim rozdziale nie powiedzieliśmy całej prawdy: sama adnotacja @Entity nie wystarczy do zmapowania klasy utrwalania. Potrzebna jest również adnotacja @Id, tak jak pokazaliśmy na poniższym listingu. Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 99 Listing 4.1. Zmapowana encja Item z właściwością identyfikatora ŚCIEŻKA: /model/src/main/java/org/jpwh/model/simple/Item.java @Entity public class Item { @Id @GeneratedValue(generator = ID_GENERATOR ) protected Long id; public Long getId() { return id; } } Opcjonalne, ale przydatne To najprostsza klasa encji oznaczona jako „zdolna do utrwalania” za pomocą adnotacji @Entity oraz zawierająca mapowanie @Id dla właściwości identyfikatora bazy danych. Domyślnie klasa jest mapowana do tabeli o nazwie ITEM w schemacie bazy danych. Każda klasa encji musi mieć właściwość @Id. W ten sposób specyfikacja JPA udostęp- nia tożsamość bazy danych do aplikacji. Nie pokazujemy właściwości identyfikatora na naszych diagramach. Zakładamy, że każda klasa encji ma identyfikator. W naszych przykładach właściwości identyfikatora zawsze nadajemy nazwę id. Jest to dobra prak- tyka projektowa. Warto stosować tę samą nazwę właściwości identyfikatora dla wszyst- kich klas encji modelu dziedziny. Jeśli nie wprowadzimy innych specyfikacji, to ta właściwość będzie zmapowana do kolumny klucza głównego o nazwie ID tabeli ITEM należącej do schematu bazy danych. Podczas ładowania i zapisywania elementów, aby uzyskać dostęp do wartości właści- wości identyfikatora, framework Hibernate skorzysta z pola, a nie z metod gettera lub settera. Ponieważ adnotacja @Id dotyczy pola, framework Hibernate domyślnie zezwoli na to, aby każde pole klasy było utrwalaną właściwością. W specyfikacji JPA istnieje następująca reguła: jeżeli zdefiniowano adnotację @Id dla pola, to JPA będzie korzystał z pól klasy bezpośrednio i domyślnie uzna wszystkie pola za część utrwalanego stanu. Sposób przesłonięcia tej własności opisaliśmy w dalszej części tego rozdziału. Z naszych doświadczeń wynika, że dostęp do pól jest zwykle najlepszym wyborem, ponieważ pozostawia znacznie więcej swobody podczas projektowania metod dostępowych. Czy należy zdefiniować (publiczną) metodę gettera dla właściwości identyfikatora? W aplikacjach często wykorzystuje się identyfikatory bazy danych jako wygodne uchwyty określonego egzemplarza — nawet poza warstwą utrwalania. Przykładowo w aplikacjach webowych wyniki wyszukiwania są powszechnie wyświetlane w formie listy podsumo- wań. Gdy użytkownik wybierze konkretny element, aplikacja może potrzebować pobra- nia wybranej pozycji. Do tego celu powszechnie wykorzystuje się wyszukiwanie według identyfikatora. Prawdopodobnie już korzystałeś z identyfikatorów w taki sposób — nawet w tych aplikacjach, które bazują na JDBC. Czy należy zdefiniować metodę settera? Wartości kluczy głównych nigdy się nie zmieniają, dlatego nie należy pozwalać na modyfikowanie wartości właściwości identy- fikatora. Framework Hibernate nie aktualizuje kolumny klucza głównego i nie należy udostępniać publicznej metody settera dla identyfikatora encji. Poleć książkęKup książkę 100 ROZDZIAŁ 4. Mapowanie klas utrwalania Typ Javy właściwości identyfikatora — w poprzednim przykładzie java.lang.Long — zależy od typu kolumny klucza głównego tabeli ITEM oraz sposobu tworzenia wartości kluczy. To odsyła nas do adnotacji @GeneratedValue i do kluczy głównych w ogóle. 4.2.3. Wybieranie klucza głównego Identyfikator bazy danych encji jest mapowany na klucz główny jakiejś tabeli, dlatego najpierw spróbujemy omówić tematykę kluczy głównych bez zwracania uwagi na mapowanie. Spróbujmy cofnąć się o krok i zastanowić nad tym, w jaki sposób identyfi- kujemy encje. Klucz kandydat jest kolumną (albo zbiorem kolumn), którą można wykorzystać do zidentyfikowania określonego wiersza w tabeli. Aby klucz kandydat mógł zostać kluczem głównym, musi spełnić następujące wymagania:  Wartością kolumny klucza kandydata nigdy nie jest null. Nie można niczego zidentyfikować za pomocą nieznanych danych, dlatego w modelu relacyjnym nie występują wartości null. Niektóre produkty SQL pozwalają na definiowanie (złożonych) kluczy głównych z kolumnami, które mogą przyjmować wartości null, dlatego należy zachować ostrożność.  Wartość kolumny (kolumn) klucza kandydata jest unikatowa dla każdego wiersza.  Wartość kolumny (kolumn) klucza kandydata nigdy się nie zmienia. Jest niemu- towalna. Czy klucze główne muszą być niemutowalne? Klucz kandydat, zgodnie z definicją modelu relacyjnego, musi być unikatowy i niereduko- walny (żaden podzbiór atrybutów klucza nie może być niepowtarzalny). Poza koniecz- nością spełnienia tych wymagań wybór klucza kandydata, który ma pełnić funkcję klucza głównego, jest kwestią gustu. Framework Hibernate oczekuje jednak, aby klucz kandydat używany w roli klucza głównego był niezmienny. Hibernate nie wspiera aktualizowania wartości klucza głównego za pośrednictwem API. Przy próbie obejścia tego wymagania możemy napotkać problemy z mechanizmami buforowania i sprawdzania aktualizacji frameworka. Jeżeli schemat bazy danych jest oparty na kluczach głównych dających się aktualizować (i być może używa ograniczeń ON UPDATE CASCADE), to trzeba zmodyfikować ten schemat, aby mógł działać z Hibernate. Jeżeli tabela ma tylko jeden identyfikujący atrybut, to z definicji staje się on kluczem głównym. Jednak w przypadku konkretnej tabeli te funkcje może spełniać kilka kolumn albo kombinacja kilku kolumn. Aby zdecydować o tym, który klucz główny dla tabeli będzie najlepszy, należy dokonać wyboru spośród kluczy kandydatów. Klucze kandy- datów niewybrane do roli klucza głównego należy zadeklarować w bazie danych jako unikatowe, jeśli ich wartość jest rzeczywiście unikatowa (ale być może nie jest nie- zmienna). W wielu klasycznych modelach danych SQL używane są naturalne klucze główne. Klucz naturalny to taki, który ma znaczenie biznesowe: jest atrybutem lub kombinacją atrybutów unikatową ze względu na biznesową semantykę. Przykładami naturalnych kluczy obcych jest numer ubezpieczenia społecznego w Stanach Zjednoczonych lub numer PESEL w Polsce. Rozpoznanie kluczy naturalnych jest bardzo proste: jeżeli Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 101 atrybut klucza kandydata ma znaczenie na zewnątrz kontekstu bazy danych, to jest to klucz naturalny bez względu na to, czy jest on generowany automatycznie. Należy pomyśleć o użytkownikach aplikacji: jeżeli pracując z aplikacją i rozmawiając na jej temat, użytkownicy odwołują się do atrybutu klucza, to jest to naturalny klucz (na przykład: „Czy możesz wysłać mi zdjęcia towaru 123-abc”?). Z doświadczenia wiemy, że naturalne klucze główne zazwyczaj sprawiają problemy. Dobry klucz główny musi być unikatowy, niezmienny i nigdy nie może mieć wartości null. Niewiele atrybutów encji spełnia te wymagania, a te, które to robią, nie mogą być skutecznie indeksowane w bazach danych SQL (chociaż to jest szczegół implementacji, który nie powinien być czynnikiem decydującym i przemawiającym za jakimś kluczem albo przeciwko niemu). Ponadto trzeba mieć pewność, że definicja klucza kandydata nigdy się nie zmieni przez cały czas życia bazy danych. Zmienianie wartości (albo nawet definicji) klucza głównego i wszystkich kluczy obcych, które się do niego odwo- łują, jest frustrującym zadaniem. Należy oczekiwać od schematu bazy danych przetrwa- nia dziesięcioleci nawet wtedy, kiedy czas życia aplikacji będzie krótszy. Co więcej, naturalne klucze kandydatów często można znaleźć, jedynie łącząc kilka kolumn w złożony klucz naturalny. Takie złożone klucze, chociaż na pewno właściwe dla niektórych artefaktów schematu (jak tabele łączące w relacji wiele-do-wielu), poten- cjalnie znacznie utrudniają utrzymanie bazy danych, tworzenie zapytań ad hoc oraz ewolucję schematu. Tematykę kluczy głównych omówimy w dalszej części tej książki, w punkcie 9.2.1. Z tych powodów zalecamy posługiwanie się sztucznymi identyfikatorami, nazy- wanymi również kluczami zastępczymi. Klucze zastępcze nie mają żadnego bizneso- wego znaczenia — mają unikatowe wartości wygenerowane przez bazę danych albo aplikację. Użytkownicy aplikacji w idealnej sytuacji nie wiedzą o istnieniu tych kluczy ani nie odwołują się do ich wartości. Są one wewnętrzną częścią systemu. Wprowadze- nie kolumny klucza zastępczego jest także odpowiednie w często spotykanej sytuacji, kiedy nie ma kluczy kandydatów. Inaczej mówiąc: w (prawie) każdej tabeli należącej do schematu powinna występować dedykowana kolumna klucza zastępczego służąca tylko temu celowi. Istnieje kilka dobrze znanych sposobów generowania wartości kluczy zastępczych. Konfiguruje się je za pomocą wspomnianej wyżej adnotacji @GeneratedValue. 4.2.4. Konfigurowanie generatorów kluczy Do oznaczenia właściwość identyfikatora klasy encji potrzebna jest adnotacja @Id. Jeżeli nie użyjemy razem z nią adnotacji @GeneratedValue, to dostawca JPA zakłada, że przed zapisaniem egzemplarza klasy zadbamy o utworzenie i przypisanie jego identyfikatora. Nazywamy go identyfikatorem przypisanym przez aplikację. Przypisywanie identyfi- katora encji ręcznie jest konieczne w przypadku, gdy mamy do czynienia ze starszymi bazami danych i (lub) naturalnymi kluczami głównymi. Więcej na temat tego rodzaju mapowania opowiemy w punkcie 9.2.1, który jest dedykowany temu tematowi. Zwykle chcemy, aby system wygenerował wartość klucza głównego podczas zapi- sywania egzemplarza encji, dlatego umieszczamy adnotację @GeneratedValue obok adno- tacji @Id. Specyfikacja JPA standaryzuje kilka strategii generowania wartości za pomocą Poleć książkęKup książkę 102 ROZDZIAŁ 4. Mapowanie klas utrwalania wartości typu wyliczeniowego javax.persistence.GenerationType, którą wybieramy, przypisując @GeneratedValue(strategy = ...):  GenerationType.AUTO — Hibernate wybiera właściwą strategię na podstawie dialektu SQL skonfigurowanej bazy danych. Jest to równoważne adnotacji @GeneratedValue() bez jakichkolwiek ustawień.  GenerationType.SEQUENCE — Hibernate oczekuje w bazie danych sekwencji HIBERNATE_SEQUENCE (tworzy ją, jeśli posługujemy się odpowiednimi narzędziami). Sekwencja ta będzie wywoływana osobno przed każdą instrukcją INSERT, by wygenerować sekwencyjne wartości liczbowe.  GenerationType.IDENTITY — Hibernate oczekuje w bazie danych specjalnej, auto- inkrementowanej kolumny klucza głównego, która w momencie wykonania instrukcji INSERT automatycznie wygeneruje wartość liczbową (Hibernate tworzy taką kolumnę za pomocą języka DDL).  GenerationType.TABLE — Hibernate korzysta z dodatkowej tabeli w schemacie bazy danych, w której są zapisane następne liczbowe wartości kluczy głów- nych — po jednym wierszu na każdą klasę encji. Wartości z tej tabeli są odczy- tywane i odpowiednio aktualizowane przed wykonaniem instrukcji INSERT. Domyślna nazwa tabeli to HIBERNATE_SEQUENCES, natomiast nazwy kolumn to SEQUENCE_NAME i SEQUENCE_NEXT_HI_VALUE (w wewnętrznej implementacji zastoso- wano złożony, ale wydajny algorytm generowania największych i najmniejszych wartości; więcej informacji na ten temat później). Chociaż ustawienie AUTO wydaje się wygodne, to zwykle potrzebujemy większej kon- troli. Z tego powodu nie powinniśmy na nim polegać, a zamiast niego jawnie skonfi- gurować strategię generowania klucza głównego. Ponadto większość aplikacji działa z sekwencjami bazy danych, ale czasami zachodzi potrzeba spersonalizowania nazwy i innych ustawień sekwencji. Dlatego zamiast wybierania jednej ze strategii JPA, zale- camy zmapowanie identyfikatora za pomocą adnotacji @GeneratedValue(generator= ID_ GENERATOR ), tak jak to pokazaliśmy w poprzednim przykładzie. Jest to niestandardowy generator identyfikatorów. Można teraz skonfigurować usta- wienie ID_GENERATOR niezależnie od klas encji. Specyfikacja JPA obejmuje dwie wbudowane adnotacje, z których można skorzystać do skonfigurowania generatorów identyfikowanych przez nazwę: @javax.persistence. SequenceGenerator oraz @javax.persistence.TableGenerator. Za pomocą tych adnotacji można stworzyć generator z własnymi nazwami sekwencji i tabeli. Jak zwykle bywa w przypadku adnotacji JPA, niestety można ich używać tylko na początku (być może w innym przypadku pustej) klasy, a nie w pliku package-info.java. Własność frameworka Hibernate Z tego powodu, a także dlatego, że adnotacje JPA nie dają nam dostępu do pełnego zbioru funkcji Hibernate, zalecamy rozwiązanie alternatywne: natywną adnotację @org.hibernate.annotations.GenericGenerator. Adnotacja ta obsługuje wszystkie strategie generatora identyfikatorów oraz szczegółów konfiguracji. W przeciwieństwie do raczej Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 103 ograniczonych adnotacji JPA, możemy skorzystać z adnotacji Hibernate w pliku package-info.java, zazwyczaj umieszczonego w tym samym pakiecie, w którym są umiesz- czone klasy modelu dziedziny. Rekomendowaną konfigurację zaprezentowaliśmy na poniższym listingu. Listing 4.2. Generator identyfikatorów frameworka Hibernate skonfigurowany jako metadane na poziomie pakietu ŚCIEŻKA: /model/src/main/java/org/jpwh/model/package-info.java strategia enhanced-sequence @org.hibernate.annotations.GenericGenerator( name = ID_GENERATOR , strategy = enhanced-sequence , parameters = { @org.hibernate.annotations.Parameter( name = sequence_name , value = JPWH_SEQUENCE ), @org.hibernate.annotations.Parameter( name = initial_value , value = 1000 ) }) nazwa sekwencji wartość początkowa Stosowanie tej specyficznej dla Hibernate konfiguracji generatora przynosi następujące korzyści:  Strategia enhanced-sequence generuje sekwencyjne wartości liczbowe. Jeżeli stosowany dialekt SQL obsługuje sekwencje, to Hibernate skorzysta z sekwencji w bazie danych. Jeśli wykorzystywany system DBMS nie wspiera natywnych sekwencji, to framework Hibernate skorzysta z dodatkowej „tabeli sekwencji”, która symuluje zachowanie sekwencji. W ten sposób zyskujemy rzeczywistą przenośność: przed wykonaniem instrukcji SQL INSERT zawsze można wywołać program generujący. Takiej swobody nie ma na przykład w przypadku stosowania automatycznie inkrementowanych kolumn identyfikatorów, które w momencie wykonania instrukcji INSERT generują wartość zwracaną później do aplikacji.  Możemy skonfigurować nazwę sekwencji . Hibernate skorzysta z istniejącej sekwencji albo utworzy ją automatycznie podczas generowania schematu SQL. Jeżeli system DBMS nie obsługuje sekwencji, to będzie to nazwa specjalnej „tabeli sekwencji”.  Możemy rozpocząć od wskazanej wartości początkowej . Dostępność tego ustawienia daje nam przestrzeń do wykorzystywania danych testowych. Przy- kładowo przy próbie uruchomienia testów integracyjnych Hibernate będzie wprowadzać nowe dane z kodu testów o wartościach identyfikatora większych niż 1000. Dowolne dane testowe, które chcemy zaimportować przed testem, mogą posługiwać się wartościami od 1 do 999, a w testach możemy posługiwać się sta- bilnymi wartościami identyfikatorów: „załaduj towar o identyfikatorze 123 i uruchom na nim jakieś testy”. Opcja jest stosowana w momencie, gdy Hibernate generuje schemat SQL i sekwencję. Jest to opcja DDL. Poleć książkęKup książkę 104 ROZDZIAŁ 4. Mapowanie klas utrwalania Tę samą sekwencję bazy danych możemy współdzielić pomiędzy wszystkimi klasami modelu dziedziny. Nie ma żadnych przeszkód, aby adnotacja @GeneratedValue(generator = ID_GENERATOR ) została umieszczona w klasach wszystkich encji. Nie ma znaczenia, czy wartości klucza głównego są ciągłe dla jakiejś konkretnej encji, jednak pod warun- kiem że są unikatowe w ramach jednej tabeli. W przypadkach gdy ma znaczenie rywa- lizacja (ponieważ sekwencja musi być wywołana przed każdą instrukcją INSERT), można zastosować odmianę omawianej konfiguracji generatora. Omówimy ją później, w pod- rozdziale 20.1. W roli typu właściwości identyfikatora w klasie encji używamy klasy java.lang.Long, co doskonale pasuje do liczbowego generatora sekwencji bazy danych. Można by również skorzystać z prymitywu long. Główna różnica polega na wartości zwracanej przez wywołanie someItem.getId() na nowym egzemplarzu, który jeszcze nie został zapisany do bazy danych: null albo 0. Przy sprawdzaniu, czy określony egzemplarz jest nowy, test na wartość null jest prawdopodobnie bardziej zrozumiały dla osoby z zewnątrz, która czyta nasz kod. Dla identyfikatorów nie należy stosować innego typu całkowito- liczbowego, takiego jak int albo short. Chociaż przez pewien czas mogą one działać (być może nawet przez wiele lat), to ze względu na to, że z czasem baza danych będzie się powiększać, możemy być ograniczeni ich zakresem. Jeżeli nowy identyfikator byłby generowany co jedną milisekundę bez żadnych przerw, to rozwiązanie bazujące na typie int działałoby przez prawie dwa miesiące, natomiast w przypadku skorzystania z typu long wystarczyłoby na około 300 milionów lat. Strategia enhanced-sequence pokazana na listingu 4.2 to zalecana strategia sekwencji dla większości aplikacji. Jest to jednak tylko jedna z wbudowanych strategii dostępnych dla frameworka Hibernate. Własność frameworka Hibernate 4.2.5. Strategie generatorów identyfikatorów Poniżej zamieściliśmy listę wszystkich dostępnych strategii identyfikatorów genera- torów, ich opcji oraz naszych zaleceń dotyczących ich użycia. Jeżeli nie chcesz teraz czytać całej tej listy, włącz opcję GenerationType.AUTO i sprawdź domyślne zachowanie frameworka Hibernate dla wybranego dialektu bazy danych. Istnieje duże prawdopo- dobieństwo, że strategie sequence bądź identity będą dobre, ale nie będą to opcje najbardziej wydajne lub przenośne. Jeżeli potrzebujesz spójnego i przenośnego zacho- wania oraz wartości identyfikatorów dostępnych przed wykonaniem instrukcji INSERT, skorzystaj ze strategii enhanced-sequence zaprezentowanej w poprzednim punkcie. To przenośna, elastyczna i nowoczesna strategia, która dodatkowo oferuje różne optymali- zatory dla dużych zbiorów danych. Pokażemy również relację pomiędzy każdą ze standardowych strategii JPA a natywnym odpowiednikiem Hibernate. Framework Hibernate rozwijał się organicznie. Z tego powodu mamy teraz dwa zbiory mapowania pomiędzy standardową a natywną stra- tegią — na liście będą one nazywane Starym i Nowym. Mapowanie można przełączyć za pomocą ustawienia hibernate.id.new_generator_mappings w pliku persistence.xml. Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 105 Generowanie identyfikatorów przed instrukcją INSERT albo po niej: jaka jest różnica? Usługa ORM próbuje zoptymalizować instrukcje SQL INSERT, na przykład łącząc je w grupy — po kilka — na poziomie JDBC. Dzięki temu wykonanie instrukcji SQL podczas jednostki pracy następuje jak najpóźniej, a nie w chwili wywołania entityManager.persist(someItem). Wywo- łanie umieszcza jedynie instrukcję wstawiania w kolejce do późniejszego wykonania, a jeśli to możliwe, przypisuje encji wartość identyfikatora. Jednak jeżeli wtedy wywołamy someItem.getId(), to możemy uzyskać wartość null, jeśli silnik nie zdoła wygenerować identyfikatora przed instrukcją INSERT. Ogólnie rzecz biorąc, preferujemy strategie gene- rowania pre-insert. W wyniku zastosowania tych strategii wartości identyfikatorów są generowane niezależnie — przed wykonaniem instrukcji INSERT. Powszechnie wybieraną opcją jest współdzielona i dostępna równolegle sekwencja bazy danych. Kolumny autoin- krementowane, domyślne wartości kolumn albo klucze generowane za pomocą wyzwa- laczy są dostępne wyłącznie po wykonaniu instrukcji INSERT. Domyślna wartość to true, co odpowiada Nowemu mapowaniu. Oprogramowanie nie starzeje się tak dobrze, jak wino:  native — powoduje automatyczny wybór innych strategii, takich jak sequence lub identity, w zależności od skonfigurowanego dialektu SQL. Wymaga przeglą- dania dokumentacji Javadoc (albo nawet kodu źródłowego) dialektu SQL skonfi- gurowanego w pliku persistence.xml. Odpowiednik JPA GenerationType.AUTO w Starym mapowaniu.  sequence — wykorzystuje natywną sekwencję bazy danych o nazwie HIBERNATE_ SEQUENCE. Sekwencja jest wywoływana przed każdą instrukcją INSERT dla nowego wiersza. Możemy spersonalizować nazwę sekwencji oraz wprowadzić dodatkowe ustawienia DDL. Więcej informacji można znaleźć w dokumentacji Javadoc dla klasy org.hibernate.id.SequenceGenerator.  sequence-identity — generuje wartości kluczy, wywołując sekwencję bazy danych podczas wstawiania wierszy do bazy danych, na przykład insert into ITEM(ID) values (HIBERNATE_SEQUENCE.nextval). Wartość klucza jest pobierana po wyko- naniu instrukcji INSERT. Jest to takie samo zachowanie jak w przypadku strategii identity. Pozwala na używanie tych samych parametrów i typów właściwości jak w przypadku strategii sequence. Więcej informacji można znaleźć w dokumentacji Javadoc klasy org.hibernate.id.SequenceIdentityGenerator oraz jej klasy nad- rzędnej.  enhanced-sequence — wykorzystuje natywną sekwencję bazy danych, kiedy to jest możliwe. W przeciwnym razie używana jest dodatkowa tabela bazy danych z pojedynczą kolumną i wierszem, emulująca sekwencję. Domyślna nazwa to HIBERNATE_SEQUENCE. „Sekwencja” bazy danych jest wywoływana zawsze przed instrukcją INSERT, dzięki czemu uzyskujemy takie samo zachowanie niezależnie od tego, czy system DBMS obsługuje rzeczywiste sekwencje. Istnieje możliwość skorzystania z optymalizatora org.hibernate.id.enhanced.Optimizer, dzięki któremu nie ma konieczności sięgania do bazy danych przed każdą instrukcją INSERT. Ustawienie domyślne to brak optymalizacji i pobieranie nowej wartości dla każdej instrukcji INSERT. Więcej przykładów można znaleźć w rozdziale 20. Opis wszystkich parametrów można znaleźć w dokumentacji Javadoc dla klasy Poleć książkęKup książkę 106 ROZDZIAŁ 4. Mapowanie klas utrwalania org.hibernate.id.enhanced.SequenceStyleGenerator. Odpowiednik JPA Generation Type.SEQUENCE oraz GenerationType.AUTO z włączonym Nowym mapowaniem. Jest to najprawdopodobniej najlepsza opcja spośród strategii wbudowanych.  seqhilo — używa natywnej sekwencji bazy danych o nazwie HIBERNATE_SEQUENCE; optymalizuje wywołania przed instrukcjami INSERT, łącząc wartości hii lo. Jeżeli wartość hi pobrana z sekwencji to 1, to następne dziewięć instrukcji wstawiania do bazy będzie wykonywanych z wartościami kluczy 11, 12, 13… 19. Później zostaje wywołana kolejna sekwencja w celu uzyskania następnej wartości hi (2 albo większej) i procedura jest powtarzana dla wartości 21, 22, 23 itd. Istnieje możliwość skonfigurowania maksymalnej wartości lo (9 to ustawienie domyślne) za pomocą parametru max_lo. Niestety, ze względu na wadę kodu frame- worka Hibernate nie można skonfigurować tej strategii za pomocą adnotacji @GenericGenerator. Jedynym sposobem skorzystania z tej strategii jest użycie usta- wienia JPA GenerationType.SEQUENCE i Starego mapowania. Istnieje możliwość skonfigurowania tej strategii za pomocą standardowej adnotacji JPA @Sequence Generator na klasie (która w innym przypadku byłaby pusta). Więcej informacji można uzyskać w dokumentacji Javadoc dla klasy org.hibernate.id.SequenceHiLo Generator i jej klasy nadrzędnej. Zamiast tej strategii warto zastanowić się nad użyciem strategii enhanced-sequence z optymalizatorem.  hilo — używa dodatkowej tabeli o nazwie HIBERNATE_UNIQUE_KEY oraz tego samego algorytmu, jak w przypadku strategii seqhilo. W tabeli występuje pojedyncza kolumna i wiersz z następną wartością sekwencji. Domyślna maksymalna wartość lo wynosi 32767, więc warto skonfigurować tę wartość za pomocą para- metru max_lo. Więcej informacji można znaleźć w dokumentacji Javadoc dla klasy org.hibernate.id.TableHiLoGenerator. Nie zalecamy stosowania tej przestarzałej strategii. Zamiast niej lepiej wykorzystać strategię enhanced-sequence wraz z optymalizatorem.  enhanced-table — używa dodatkowej tabeli o nazwie HIBERNATE_SEQUENCES, domyśl- nie z jednym wierszem reprezentującym sekwencję i przechowującym następną wartość. Ta wartość jest wybierana i aktualizowana w przypadku, kiedy musi być wygenerowana wartość identyfikatora. Generator można skonfigurować tak, aby zamiast tego wykorzystywał wiele wierszy: po jednym dla każdej sekwencji. Więcej informacji można znaleźć w dokumentacji Javadoc dla klasy org.hibernate. id.enhanced.TableGenerator. Strategia ta jest odpowiednikiem JPA Generation Type.TABLE z włączonym Nowym mapowaniem. Zastępuje przestarzały, ale podobny generator org.hibernate.id.MultipleHiLoPerTableGenerator, który jest odpowiednikiem Starego mapowania dla ustawienia JPA GenerationType.TABLE.  identity — obsługuje sekwencję IDENTITY i autoinkrementowane kolumny w bazach danych DB2, MySQL, MS SQL Server i Sybase. Wartość identyfi- katora dla kolumny klucza głównego będzie generowana dla instrukcji SQL INSERT wykonywanej dla wiersza. Nie pozwala na wprowadzanie opcji. Niestety, ze względu na wadę kodu frameworka Hibernate nie można skonfigurować tej strategii za pomocą adnotacji @GenericGenerator. Jedynym dostępnym sposobem użycia tej strategii jest zastosowanie ustawienia JPA GenerationType.IDENTITY Poleć książkęKup książkę 4.2. Mapowanie encji z tożsamością 107 oraz Starego albo Nowego mapowania, dzięki czemu strategia stanie się domyślna dla ustawienia GenerationType.IDENTITY.  increment — przy uruchamianiu frameworka Hibernate następuje odczytanie maksymalnych wartości (liczbowo) kolumn klucza głównego dla tabel każdej z encji. Za każdym razem, gdy do tych tabel są wstawiane nowe wiersze, odpo- wiednia wartość jest zwiększana o jeden. Strategia jest szczególnie skuteczna, gdy w aplikacji Hibernate bez klastrów jest wyłączny dostęp do bazy danych. Nie warto jej jednak używać w żadnym innym scenariuszu.  select — Hibernate nie wygeneruje wartości klucza ani nie uwzględni kolumny klucza głównego w instrukcji INSERT. Hibernate oczekuje od systemu DBMS przypisania do kolumny wartości (domyślnej dla schematu albo wygenerowanej za pomocą wyzwalacza) w momencie wstawiania wiersza do bazy danych. Następ- nie kiedy wiersz zostanie wstawiony do bazy, Hibernate odczytuje kolumnę klucza głównego za pomocą zapytania SELECT. Wymaganym parametrem jest key. Za jego pomocą przekazujemy do instrukcji SELECT nazwę właściwości identy- fikatora w bazie danych (na przykład id). Ta strategia nie jest zbyt wydajna i powinna być stosowana tylko ze starszymi sterownikami JDBC, które nie mogą zwrócić wygenerowanych kluczy bezpośrednio.  uuid2 — generuje w warstwie aplikacji unikatowy, 128-bitowy klucz UUID. Stra- tegia przydatna w sytuacji, gdy potrzebujemy globalnie unikatowych identyfi- katorów dla wielu baz danych (załóżmy, że co noc dane z kilku różnych produk- cyjnych baz danych są scalane partiami do archiwum). Identyfikator UUID może być kodowany w klasie encji jako java.lang.String, byte[16] albo java.util.UUID. Strategia ta zastępuje starsze strategie uuid oraz uuid.hex. Można ją skonfigu- rować za pomocą ustawienia org.hibernate.id.UUIDGenerationStrategy. Więcej informacji można znaleźć w dokumentacji Javadoc dla klasy org.hibernate. id.UUIDGenerator.  guid — wykorzystuje globalnie unikatowy identyfikator generowany przez bazę danych za pośrednictwem funkcji SQL dostępnej dla baz danych Oracle, Ingres, MS SQL Server i MySQL. Hibernate wywołuje funkcję bazy danych przed wykonaniem instrukcji INSERT. Wartość jest mapowana na właściwość identyfi- katora java.lang.String. Aby uzyskać pełną kontrolę nad generowaniem identy- fikatora, można skonfigurować strategię za pomocą adnotacji @GenericGenerator, podając w pełni kwalifikowaną nazwę klasy, która implementuje interfejs org.hibernate.id.IdentityGenerator. Podsumowując, nasze zalecenia dotyczące generatora identyfikatora są następujące:  Ogólnie rzecz biorąc, lepiej stosować strategie generowania pre-insert, polegające na niezależnym generowaniu wartości identyfikatorów przed wykonaniem instrukcji INSERT.  Lepiej też wykorzystywać strategię enhanced-sequence, która bazuje na użyciu natywnej sekwencji bazy danych, jeśli jest obsługiwana, a jeśli nie, to emuluje sekwencję za pomocą dodatkowej tabeli bazy danych z pojedynczą kolumną i wierszem. Poleć książkęKup książkę 108 ROZDZIAŁ 4. Mapowanie klas utrwalania Od tej chwili zakładamy, że właściwości identyfikatorów zostały dodane do klas encji modelu dziedziny, a
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Java Persistence. Programowanie aplikacji bazodanowych w Hibernate. Wydanie II
Autor:
, ,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: