Hibernacja - szybki przewodnik

Co to jest JDBC?

JDBC oznacza Java Database Connectivity. Udostępnia zestaw Java API do uzyskiwania dostępu do relacyjnych baz danych z programu Java. Te interfejsy API języka Java umożliwiają programom w języku Java wykonywanie instrukcji SQL i interakcję z dowolną bazą danych zgodną z SQL.

JDBC zapewnia elastyczną architekturę do pisania niezależnej od bazy danych aplikacji, która może działać na różnych platformach i współpracować z różnymi DBMS bez żadnych modyfikacji.

Plusy i minusy JDBC

Plusy JDBC Wady JDBC

Czyste i proste przetwarzanie SQL

Dobra wydajność przy dużych ilościach danych

Bardzo dobre do małych zastosowań

Prosta składnia, tak łatwa do nauczenia

Złożony, jeśli jest używany w dużych projektach

Duże koszty programowania

Brak hermetyzacji

Trudna do wdrożenia koncepcja MVC

Zapytanie jest specyficzne dla DBMS

Dlaczego mapowanie relacyjne obiektów (ORM)?

Kiedy pracujemy z systemem zorientowanym obiektowo, istnieje niezgodność między modelem obiektowym a relacyjną bazą danych. RDBMS reprezentują dane w formacie tabelarycznym, podczas gdy języki zorientowane obiektowo, takie jak Java lub C #, przedstawiają je jako połączone ze sobą wykresy obiektów.

Rozważ następującą klasę Java z odpowiednimi konstruktorami i powiązaną funkcją publiczną -

public class Employee {
   private int id;
   private String first_name; 
   private String last_name;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public String getFirstName() {
      return first_name;
   }
   
   public String getLastName() {
      return last_name;
   }
   
   public int getSalary() {
      return salary;
   }
}

Rozważ, że powyższe obiekty mają być przechowywane i wczytywane do następującej tabeli RDBMS -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Pierwszy problem, co jeśli po opracowaniu kilku stron lub naszej aplikacji będziemy musieli zmodyfikować wygląd naszej bazy danych? Po drugie, ładowanie i przechowywanie obiektów w relacyjnej bazie danych naraża nas na pięć następujących problemów z niezgodnością -

Sr.No. Niedopasowanie i opis
1

Granularity

Czasami będziesz mieć model obiektowy, który ma więcej klas niż liczba odpowiadających im tabel w bazie danych.

2

Inheritance

RDBMS nie definiują niczego podobnego do dziedziczenia, które jest naturalnym paradygmatem w obiektowych językach programowania.

3

Identity

RDBMS definiuje dokładnie jedno pojęcie „identyczności”: klucz podstawowy. Jednak Java definiuje zarówno tożsamość obiektu (a == b), jak i równość obiektów (a.equals (b)).

4

Associations

Języki zorientowane obiektowo reprezentują asocjacje przy użyciu odniesień do obiektów, podczas gdy RDBMS reprezentuje asocjację jako kolumnę klucza obcego.

5

Navigation

Sposoby uzyskiwania dostępu do obiektów w Javie i RDBMS są zasadniczo różne.

Plik Oprzedmiot-Rpodniosły Mapping (ORM) jest rozwiązaniem obsługującym wszystkie powyższe niedopasowania impedancji.

Co to jest ORM?

ORM oznacza Oprzedmiot-Rpodniosły Mapping (ORM) to technika programowania służąca do konwersji danych między relacyjnymi bazami danych a obiektowymi językami programowania, takimi jak Java, C # itp.

System ORM ma następujące zalety w porównaniu ze zwykłym JDBC -

Sr.No. Zalety
1 Niech kod biznesowy uzyskuje dostęp do obiektów zamiast tabel bazy danych.
2 Ukrywa szczegóły zapytań SQL z logiki OO.
3 Na podstawie JDBC „pod maską”.
4 Nie ma potrzeby zajmowania się implementacją bazy danych.
5 Jednostki oparte na koncepcjach biznesowych, a nie na strukturze bazy danych.
6 Zarządzanie transakcjami i automatyczne generowanie kluczy.
7 Szybki rozwój aplikacji.

Rozwiązanie ORM składa się z następujących czterech podmiotów -

Sr.No. Rozwiązania
1 API do wykonywania podstawowych operacji CRUD na obiektach trwałych klas.
2 Język lub interfejs API do określania zapytań odnoszących się do klas i właściwości klas.
3 Konfigurowalne narzędzie do określania metadanych mapowania.
4 Technika interakcji z obiektami transakcyjnymi w celu wykonywania brudnego sprawdzania, leniwego pobierania skojarzeń i innych funkcji optymalizacyjnych.

Struktury ORM Java

W Javie istnieje kilka trwałych struktur i opcji ORM. Trwała struktura to usługa ORM, która przechowuje i pobiera obiekty do relacyjnej bazy danych.

  • Enterprise JavaBeans Entity Beans
  • Java Data Objects
  • Castor
  • TopLink
  • Wiosna DAO
  • Hibernate
  • I wiele więcej

Hibernate to Oprzedmiot-Rpodniosły Mapping (ORM) dla JAVA. Jest to trwała platforma open source stworzona przez Gavina Kinga w 2001 roku. Jest to potężna, wysokowydajna usługa obiektowo-relacyjnej trwałości i zapytań dla dowolnej aplikacji Java.

Hibernacja odwzorowuje klasy Java na tabele bazy danych oraz z typów danych Java na typy danych SQL i zwalnia programistę z 95% typowych zadań programistycznych związanych z trwałością danych.

Hibernate znajduje się pomiędzy tradycyjnymi obiektami Java a serwerem bazy danych, aby obsłużyć wszystkie prace związane z utrwalaniem tych obiektów w oparciu o odpowiednie mechanizmy i wzorce O / R.

Zalety hibernacji

  • Hibernate dba o mapowanie klas Java do tabel bazy danych przy użyciu plików XML i bez pisania żadnej linii kodu.

  • Zapewnia proste interfejsy API do przechowywania i pobierania obiektów Java bezpośrednio do iz bazy danych.

  • Jeśli nastąpiła zmiana w bazie danych lub w dowolnej tabeli, należy zmienić tylko właściwości pliku XML.

  • Abstrahuje od nieznanych typów SQL i zapewnia sposób obejścia znanych obiektów Java.

  • Hibernate nie wymaga do działania serwera aplikacji.

  • Manipuluje złożonymi skojarzeniami obiektów bazy danych.

  • Minimalizuje dostęp do bazy danych dzięki inteligentnym strategiom pobierania.

  • Zapewnia proste zapytania dotyczące danych.

Obsługiwane bazy danych

Hibernate obsługuje prawie wszystkie główne systemy RDBMS. Poniżej znajduje się lista kilku silników baz danych obsługiwanych przez Hibernate -

  • Silnik bazy danych HSQL
  • DB2/NT
  • MySQL
  • PostgreSQL
  • FrontBase
  • Oracle
  • Baza danych Microsoft SQL Server
  • Sybase SQL Server
  • Informix Dynamic Server

Obsługiwane technologie

Hibernate obsługuje wiele innych technologii, w tym -

  • XDoclet Spring
  • J2EE
  • Wtyczki Eclipse
  • Maven

Hibernate ma warstwową architekturę, która pomaga użytkownikowi działać bez znajomości podstawowych interfejsów API. Hibernate wykorzystuje bazę danych i dane konfiguracyjne do świadczenia usług trwałych (i trwałych obiektów) dla aplikacji.

Poniżej przedstawiono bardzo wysoki poziom architektury aplikacji Hibernate.

Poniżej znajduje się szczegółowy widok architektury aplikacji Hibernate z jej ważnymi klasami podstawowymi.

Hibernate wykorzystuje różne istniejące API Java, takie jak JDBC, Java Transaction API (JTA) oraz Java Naming and Directory Interface (JNDI). JDBC zapewnia podstawowy poziom abstrakcji funkcjonalności typowej dla relacyjnych baz danych, umożliwiając obsługę przez Hibernate prawie każdej bazy danych ze sterownikiem JDBC. JNDI i JTA umożliwiają integrację Hibernate z serwerami aplikacji J2EE.

Poniższa sekcja zawiera krótki opis każdego z obiektów klas związanych z architekturą aplikacji Hibernate.

Obiekt konfiguracji

Obiekt konfiguracyjny to pierwszy obiekt Hibernacji utworzony w dowolnej aplikacji Hibernate. Zwykle jest tworzony tylko raz podczas inicjalizacji aplikacji. Reprezentuje plik konfiguracyjny lub właściwości wymagany przez Hibernate.

Obiekt Configuration udostępnia dwa kluczowe komponenty -

  • Database Connection- Jest to obsługiwane przez jeden lub więcej plików konfiguracyjnych obsługiwanych przez Hibernate. Te pliki sąhibernate.properties i hibernate.cfg.xml.

  • Class Mapping Setup - Ten komponent tworzy połączenie między klasami Java i tabelami bazy danych.

Obiekt SessionFactory

Obiekt konfiguracyjny służy do tworzenia obiektu SessionFactory, który z kolei konfiguruje Hibernate dla aplikacji przy użyciu dostarczonego pliku konfiguracyjnego i umożliwia utworzenie instancji obiektu Session. SessionFactory to obiekt bezpieczny dla wątków i używany przez wszystkie wątki aplikacji.

SessionFactory to obiekt ciężki; jest zwykle tworzony podczas uruchamiania aplikacji i przechowywany do późniejszego wykorzystania. Potrzebny byłby jeden obiekt SessionFactory na bazę danych przy użyciu oddzielnego pliku konfiguracyjnego. Tak więc, jeśli używasz wielu baz danych, musisz utworzyć wiele obiektów SessionFactory.

Obiekt sesji

Sesja służy do uzyskania fizycznego połączenia z bazą danych. Obiekt Session jest lekki i zaprojektowany do jego tworzenia za każdym razem, gdy wymagana jest interakcja z bazą danych. Trwałe obiekty są zapisywane i pobierane za pośrednictwem obiektu Session.

Obiekty sesji nie powinny być otwarte przez długi czas, ponieważ zwykle nie są bezpieczne dla wątków i powinny być tworzone i niszczone w razie potrzeby.

Przedmiot transakcji

Transakcja reprezentuje jednostkę pracy z bazą danych, a większość RDBMS obsługuje funkcje transakcji. Transakcje w Hibernate są obsługiwane przez bazowego menedżera transakcji i transakcje (z JDBC lub JTA).

Jest to obiekt opcjonalny i aplikacje Hibernate mogą nie używać tego interfejsu, zamiast tego zarządzać transakcjami we własnym kodzie aplikacji.

Zapytanie o obiekt

Obiekty zapytań używają łańcucha SQL lub języka Hibernate Query Language (HQL) do pobierania danych z bazy danych i tworzenia obiektów. Wystąpienie Query służy do wiązania parametrów zapytania, ograniczania liczby wyników zwracanych przez zapytanie i wreszcie do wykonywania zapytania.

Kryteria Obiekt

Obiekty kryteriów służą do tworzenia i wykonywania zapytań kryteriów zorientowanych obiektowo w celu pobrania obiektów.

W tym rozdziale wyjaśniono, jak zainstalować Hibernate i inne powiązane pakiety, aby przygotować środowisko dla aplikacji Hibernate. Będziemy pracować z bazą danych MySQL, aby eksperymentować z przykładami Hibernate, więc upewnij się, że masz już konfigurację bazy danych MySQL. Więcej informacji na temat MySQL można znaleźć w naszym samouczku MySQL .

Pobieranie Hibernate

Zakłada się, że masz już zainstalowaną najnowszą wersję Java w swoim systemie. Poniżej przedstawiono proste kroki, aby pobrać i zainstalować Hibernację w systemie -

  • Wybierz, czy chcesz zainstalować Hibernate w systemie Windows, czy Unix, a następnie przejdź do następnego kroku, aby pobrać plik .zip dla systemu Windows i plik .tz dla systemu Unix.

  • Pobierz najnowszą wersję Hibernate z http://www.hibernate.org/downloads.

  • W momencie pisania tego samouczka pobrałem hibernate-distribution3.6.4.Final a po rozpakowaniu pobranego pliku da ci strukturę katalogów, jak pokazano na poniższym obrazku

Instalowanie Hibernate

Po pobraniu i rozpakowaniu najnowszej wersji pliku instalacyjnego Hibernate należy wykonać dwa proste kroki. Upewnij się, że odpowiednio ustawiasz zmienną CLASSPATH, w przeciwnym razie napotkasz problem podczas kompilacji aplikacji.

  • Teraz skopiuj wszystkie pliki biblioteki z /lib do swojej CLASSPATH i zmień zmienną classpath, aby obejmowała wszystkie pliki JAR -

  • Na koniec skopiuj hibernate3.jarplik do CLASSPATH. Ten plik znajduje się w katalogu głównym instalacji i jest podstawowym plikiem JAR, którego Hibernate potrzebuje do wykonania swojej pracy.

Wymagania wstępne dotyczące hibernacji

Poniżej znajduje się lista pakietów / bibliotek wymaganych przez Hibernate i powinieneś je zainstalować przed uruchomieniem Hibernate. Aby zainstalować te pakiety, będziesz musiał skopiować pliki bibliotek z/lib do swojej CLASSPATH i odpowiednio zmień zmienną CLASSPATH.

Sr.No. Pakiety / biblioteki
1

dom4j

Analiza XML www.dom4j.org/

2

Xalan

Procesor XSLT https://xml.apache.org/xalan-j/

3

Xerces

Xerces Java Parser https://xml.apache.org/xerces-j/

4

cglib

Odpowiednie zmiany w klasach Java w czasie wykonywania http://cglib.sourceforge.net/

5

log4j

Rejestrowanie Faremwork https://logging.apache.org/log4j

6

Commons

Logowanie, e-mail itp. https://jakarta.apache.org/commons

7

SLF4J

Logging Facade for Java https://www.slf4j.org

Hibernate wymaga wcześniejszej wiedzy - gdzie znaleźć informacje o mapowaniu, które definiują, w jaki sposób klasy Java odnoszą się do tabel bazy danych. Hibernacja wymaga również zestawu ustawień konfiguracyjnych związanych z bazą danych i innymi powiązanymi parametrami. Wszystkie takie informacje są zwykle dostarczane jako standardowy plik właściwości Java o nazwiehibernate.propertieslub jako plik XML o nazwie hibernate.cfg.xml.

Rozważę plik w formacie XML hibernate.cfg.xmlaby określić wymagane właściwości Hibernate w moich przykładach. Większość właściwości przyjmuje wartości domyślne i nie jest wymagane określanie ich w pliku właściwości, chyba że jest to naprawdę wymagane. Ten plik jest przechowywany w katalogu głównym ścieżki klas aplikacji.

Właściwości hibernacji

Poniżej znajduje się lista ważnych właściwości, które należy skonfigurować dla baz danych w sytuacji autonomicznej -

Sr.No. Właściwości i opis
1

hibernate.dialect

Ta właściwość sprawia, że ​​Hibernate generuje odpowiedni kod SQL dla wybranej bazy danych.

2

hibernate.connection.driver_class

Klasa sterownika JDBC.

3

hibernate.connection.url

Adres URL JDBC do instancji bazy danych.

4

hibernate.connection.username

Nazwa użytkownika bazy danych.

5

hibernate.connection.password

Hasło bazy danych.

6

hibernate.connection.pool_size

Ogranicza liczbę połączeń oczekujących w puli połączeń bazy danych Hibernate.

7

hibernate.connection.autocommit

Umożliwia użycie trybu automatycznego zatwierdzania dla połączenia JDBC.

Jeśli używasz bazy danych wraz z serwerem aplikacji i JNDI, musisz skonfigurować następujące właściwości -

Sr.No. Właściwości i opis
1

hibernate.connection.datasource

Nazwa JNDI zdefiniowana w kontekście serwera aplikacji, którego używasz dla aplikacji.

2

hibernate.jndi.class

Klasa InitialContext dla JNDI.

3

hibernate.jndi.<JNDIpropertyname>

Przekazuje dowolną właściwość JNDI do obiektu JNDI InitialContext .

4

hibernate.jndi.url

Zawiera adres URL dla JNDI.

5

hibernate.connection.username

Nazwa użytkownika bazy danych.

6

hibernate.connection.password

Hasło bazy danych.

Hibernuj z bazą danych MySQL

MySQL to jeden z najpopularniejszych obecnie dostępnych systemów baz danych typu open source. Stwórzmyhibernate.cfg.xmlplik konfiguracyjny i umieść go w katalogu głównym ścieżki klas aplikacji. Będziesz musiał się upewnić, że masztestdb baza danych dostępna w Twojej bazie danych MySQL i masz użytkownika test dostęp do bazy danych.

Plik konfiguracyjny XML musi być zgodny z DTD konfiguracji Hibernate 3, który jest dostępny pod adresem http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
      
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>
      
      <!-- Assume test is the database name -->
      
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
      
      <property name = "hibernate.connection.username">
         root
      </property>
      
      <property name = "hibernate.connection.password">
         root123
      </property>
      
      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>
      
   </session-factory>
</hibernate-configuration>

Powyższy plik konfiguracyjny zawiera <mapping> tagi, które są powiązane z plikiem mapowania hibernacji, a zobaczymy w następnym rozdziale, czym dokładnie jest plik mapowania hibernacji oraz jak i dlaczego go używamy?

Poniżej znajduje się lista różnych ważnych typów właściwości dialektu baz danych -

Sr.No. Właściwość bazy danych i dialektu
1

DB2

org.hibernate.dialect.DB2Dialect

2

HSQLDB

org.hibernate.dialect.HSQLDialect

3

HypersonicSQL

org.hibernate.dialect.HSQLDialect

4

Informix

org.hibernate.dialect.InformixDialect

5

Ingres

org.hibernate.dialect.IngresDialect

6

Interbase

org.hibernate.dialect.InterbaseDialect

7

Microsoft SQL Server 2000

org.hibernate.dialect.SQLServerDialect

8

Microsoft SQL Server 2005

org.hibernate.dialect.SQLServer2005Dialect

9

Microsoft SQL Server 2008

org.hibernate.dialect.SQLServer2008Dialect

10

MySQL

org.hibernate.dialect.MySQLDialect

11

Oracle (any version)

org.hibernate.dialect.OracleDialect

12

Oracle 11g

org.hibernate.dialect.Oracle10gDialect

13

Oracle 10g

org.hibernate.dialect.Oracle10gDialect

14

Oracle 9i

org.hibernate.dialect.Oracle9iDialect

15

PostgreSQL

org.hibernate.dialect.PostgreSQLDialect

16

Progress

org.hibernate.dialect.ProgressDialect

17

SAP DB

org.hibernate.dialect.SAPDBDialect

18

Sybase

org.hibernate.dialect.SybaseDialect

19

Sybase Anywhere

org.hibernate.dialect.SybaseAnywhereDialect

Sesja służy do uzyskania fizycznego połączenia z bazą danych. Obiekt Session jest lekki i zaprojektowany do jego tworzenia za każdym razem, gdy wymagana jest interakcja z bazą danych. Trwałe obiekty są zapisywane i pobierane za pośrednictwem obiektu Session.

Obiekty sesji nie powinny być otwarte przez długi czas, ponieważ zwykle nie są bezpieczne dla wątków i powinny być tworzone i niszczone w razie potrzeby. Główną funkcją sesji jest oferowanie, tworzenie, odczytywanie i usuwanie operacji dla instancji mapowanych klas jednostek.

Instancje mogą istnieć w jednym z następujących trzech stanów w danym momencie -

  • transient - Nowa instancja klasy trwałej, która nie jest powiązana z sesją i nie ma reprezentacji w bazie danych, a żadna wartość identyfikatora nie jest uważana za przejściową przez Hibernate.

  • persistent- Możesz uczynić przejściową instancję trwałą, kojarząc ją z sesją. Trwała instancja ma reprezentację w bazie danych, wartość identyfikatora i jest powiązana z sesją.

  • detached - Po zamknięciu sesji hibernacji instancja trwała stanie się instancją odłączoną.

Wystąpienie sesji można serializować, jeśli jego trwałe klasy są możliwe do serializacji. Typowa transakcja powinna używać następującego idiomu -

Session session = factory.openSession();
Transaction tx = null;

try {
   tx = session.beginTransaction();
   // do some work
   ...
   tx.commit();
}

catch (Exception e) {
   if (tx!=null) tx.rollback();
   e.printStackTrace(); 
} finally {
   session.close();
}

Jeśli sesja zgłasza wyjątek, transakcja musi zostać wycofana, a sesja musi zostać odrzucona.

Metody interfejsu sesji

Istnieje wiele metod udostępnianych przez Sessioninterfejs, ale mam zamiar wymienić tylko kilka ważnych metod, których użyjemy w tym samouczku. Pełną listę metod powiązanych z programem Hibernate można znaleźć w dokumentacji HibernateSession i SessionFactory.

Sr.No. Metody i opis sesji
1

Transaction beginTransaction()

Rozpocznij jednostkę pracy i zwróć powiązany obiekt transakcji.

2

void cancelQuery()

Anuluj wykonanie bieżącego zapytania.

3

void clear()

Całkowicie wyczyść sesję.

4

Connection close()

Zakończ sesję, zwalniając połączenie JDBC i czyszcząc.

5

Criteria createCriteria(Class persistentClass)

Utwórz nową instancję Criteria dla danej klasy encji lub nadklasę klasy encji.

6

Criteria createCriteria(String entityName)

Utwórz nową instancję Criteria dla podanej nazwy jednostki.

7

Serializable getIdentifier(Object object)

Zwróć wartość identyfikatora danej jednostki skojarzonej z tą sesją.

8

Query createFilter(Object collection, String queryString)

Utwórz nowe wystąpienie zapytania dla danej kolekcji i ciągu filtru.

9

Query createQuery(String queryString)

Utwórz nowe wystąpienie zapytania dla danego ciągu zapytania HQL.

10

SQLQuery createSQLQuery(String queryString)

Utwórz nowe wystąpienie SQLQuery dla danego ciągu zapytania SQL.

11

void delete(Object object)

Usuń trwałą instancję z magazynu danych.

12

void delete(String entityName, Object object)

Usuń trwałą instancję z magazynu danych.

13

Session get(String entityName, Serializable id)

Zwróć trwałe wystąpienie danej nazwanej jednostki z podanym identyfikatorem lub null, jeśli nie ma takiego trwałego wystąpienia.

14

SessionFactory getSessionFactory()

Pobierz fabrykę sesji, która utworzyła tę sesję.

15

void refresh(Object object)

Przeczytaj ponownie stan danej instancji z podstawowej bazy danych.

16

Transaction getTransaction()

Pobierz instancję transakcji powiązaną z tą sesją.

17

boolean isConnected()

Sprawdź, czy sesja jest aktualnie połączona.

18

boolean isDirty()

Czy ta sesja zawiera jakieś zmiany, które należy zsynchronizować z bazą danych?

19

boolean isOpen()

Sprawdź, czy sesja jest nadal otwarta.

20

Serializable save(Object object)

Utrwalaj daną instancję przejściową, najpierw przypisując wygenerowany identyfikator.

21

void saveOrUpdate(Object object)

Zapisz (obiekt) lub zaktualizuj (obiekt) daną instancję.

22

void update(Object object)

Zaktualizuj instancję trwałą o identyfikator danej odłączonej instancji.

23

void update(String entityName, Object object)

Zaktualizuj instancję trwałą o identyfikator danej odłączonej instancji.

Cała koncepcja Hibernate'a polega na przejęciu wartości z atrybutów klasy Java i utrwaleniu ich w tabeli bazy danych. Dokument mapowania pomaga firmie Hibernate w określeniu, w jaki sposób wyciągnąć wartości z klas i odwzorować je na tabelę i powiązane pola.

Klasy Java, których obiekty lub instancje będą przechowywane w tabelach bazy danych, są w Hibernate nazywane klasami trwałymi. Hibernate działa najlepiej, jeśli te klasy przestrzegają kilku prostych reguł, znanych również jakoPlain Old Java Object (POJO) model programowania.

Istnieją następujące główne zasady klas trwałych, jednak żadna z nich nie jest wymaganiem twardym -

  • Wszystkie klasy Java, które zostaną utrwalone, wymagają domyślnego konstruktora.

  • Wszystkie klasy powinny zawierać identyfikator, aby umożliwić łatwą identyfikację obiektów w Hibernate i bazie danych. Ta właściwość jest mapowana na kolumnę klucza podstawowego tabeli bazy danych.

  • Wszystkie atrybuty, które zostaną utrwalone, należy zadeklarować jako prywatne i mieć getXXX i setXXX metody zdefiniowane w stylu JavaBean.

  • Główna cecha Hibernate, proxy, zależy od tego, czy klasa trwała nie jest ostateczna, albo od implementacji interfejsu, który deklaruje wszystkie metody publiczne.

  • Wszystkie klasy, które nie rozszerzają ani nie implementują niektórych wyspecjalizowanych klas i interfejsów wymaganych przez strukturę EJB.

Nazwa POJO służy do podkreślenia, że ​​dany obiekt jest zwykłym obiektem Java, a nie obiektem specjalnym, aw szczególności nie jest Enterprise JavaBean.

Prosty przykład POJO

Bazując na kilku regułach wymienionych powyżej, możemy zdefiniować klasę POJO w następujący sposób -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Mapowania obiektowe / relacyjne są zwykle definiowane w dokumencie XML. Ten plik mapowania instruuje Hibernate - jak mapować zdefiniowaną klasę lub klasy do tabel bazy danych?

Chociaż wielu użytkowników Hibernate'a decyduje się na ręczne pisanie XML, ale istnieje wiele narzędzi do generowania dokumentu mapowania. Obejmują oneXDoclet, Middlegen i AndroMDA dla zaawansowanych użytkowników Hibernacji.

Rozważmy naszą wcześniej zdefiniowaną klasę POJO, której obiekty pozostaną w tabeli zdefiniowanej w następnej sekcji.

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Byłaby jedna tabela odpowiadająca każdemu obiektowi, który chcesz zapewnić trwałość. Rozważ powyższe obiekty, które należy przechowywać i pobierać do następującej tabeli RDBMS -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Na podstawie dwóch powyższych encji możemy zdefiniować następujący plik mapowania, który instruuje Hibernate, jak mapować zdefiniowaną klasę lub klasy na tabele bazy danych.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Dokument odwzorowania należy zapisać w pliku w formacie <nazwaklasy> .hbm.xml. Zapisaliśmy nasz dokument mapowania w pliku Employee.hbm.xml.

Zobaczmy, aby zrozumieć trochę szczegółów na temat elementów mapowania używanych w pliku mapowania -

  • Dokument odwzorowania to dokument XML mający <hibernate-mapping> jako element główny, który zawiera wszystkie pliki <class> elementy.

  • Plik <class>elementy służą do definiowania określonych mapowań z klas Java do tabel bazy danych. Nazwa klasy Java jest określana przy użyciu rozszerzenianame atrybut elementu klasy i bazy danych table nazwa jest określana za pomocą atrybutu tabeli.

  • Plik <meta> element jest elementem opcjonalnym i może służyć do tworzenia opisu klasy.

  • Plik <id>element odwzorowuje unikalny atrybut ID w klasie na klucz podstawowy tabeli bazy danych. Plikname atrybut elementu id odwołuje się do właściwości w klasie, a plik columnatrybut odnosi się do kolumny w tabeli bazy danych. Pliktype atrybut posiada typ odwzorowania hibernacji, te typy odwzorowania zostaną przekonwertowane z typu danych Java na SQL.

  • Plik <generator>element w elemencie id służy do automatycznego generowania wartości klucza podstawowego. Plikclass atrybut elementu generatora jest ustawiony na native niech hibernacja podniesie się identity, sequencelub hilo algorytm tworzenia klucza podstawowego w zależności od możliwości podstawowej bazy danych.

  • Plik <property>element służy do odwzorowania właściwości klasy Java na kolumnę w tabeli bazy danych. Plikname atrybut elementu odwołuje się do właściwości w klasie, a plik columnatrybut odnosi się do kolumny w tabeli bazy danych. Pliktype atrybut posiada typ odwzorowania hibernacji, te typy odwzorowania zostaną przekonwertowane z typu danych Java na SQL.

Dostępne są inne atrybuty i elementy, które zostaną użyte w dokumencie mapowania i spróbuję omówić jak najwięcej, omawiając inne tematy związane z Hibernate.

Przygotowując dokument odwzorowania Hibernacji, można zauważyć, że mapuje się typy danych Java na typy danych RDBMS. Pliktypeszadeklarowane i użyte w plikach mapowania nie są typami danych Java; nie są też typami baz danych SQL. Te typy nazywane sąHibernate mapping types, który może tłumaczyć z języka Java na typy danych SQL i odwrotnie.

W tym rozdziale wymieniono wszystkie podstawowe typy mapowania, datę i godzinę, duże obiekty i różne inne wbudowane typy mapowania.

Typy prymitywne

Typ mapowania Typ Java Typ ANSI SQL
liczba całkowita int lub java.lang.Integer LICZBA CAŁKOWITA
długo long lub java.lang.Long BIGINT
krótki short lub java.lang.Short SMALLINT
pływak float lub java.lang.Float PŁYWAK
podwójnie double lub java.lang.Double PODWÓJNIE
big_decimal java.math.BigDecimal NUMERYCZNE
postać java.lang.String CHAR (1)
strunowy java.lang.String VARCHAR
bajt byte lub java.lang.Byte TINYINT
boolean boolean lub java.lang.Boolean KAWAŁEK
tak nie boolean lub java.lang.Boolean CHAR (1) ('Y' lub 'N')
prawda fałsz boolean lub java.lang.Boolean CHAR (1) ('T' lub 'F')

Typy daty i godziny

Typ mapowania Typ Java Typ ANSI SQL
data java.util.Date lub java.sql.Date DATA
czas java.util.Date lub java.sql.Time CZAS
znak czasu java.util.Date lub java.sql.Timestamp ZNAK CZASU
kalendarz java.util.Calendar ZNAK CZASU
calendar_date java.util.Calendar DATA

Typy obiektów binarnych i dużych

Typ mapowania Typ Java Typ ANSI SQL
dwójkowy bajt[] VARBINARY (lub BLOB)
tekst java.lang.String CLOB
serializowalny dowolna klasa Java, która implementuje java.io.Serializable VARBINARY (lub BLOB)
clob java.sql.Clob CLOB
kropelka java.sql.Blob KROPELKA

Typy związane z JDK

Typ mapowania Typ Java Typ ANSI SQL
klasa java.lang.Class VARCHAR
widownia java.util.Locale VARCHAR
strefa czasowa java.util.TimeZone VARCHAR
waluta java.util.Currency VARCHAR

Weźmy teraz przykład, aby zrozumieć, w jaki sposób możemy wykorzystać Hibernate do zapewnienia trwałości Java w samodzielnej aplikacji. Przejdziemy przez różne etapy tworzenia aplikacji Java przy użyciu technologii Hibernate.

Utwórz klasy POJO

Pierwszym krokiem w tworzeniu aplikacji jest zbudowanie klasy lub klas Java POJO, w zależności od aplikacji, która zostanie utrwalona w bazie danych. Rozważmy naszeEmployee klasa z getXXX i setXXX metody, aby uczynić ją zgodną z klasą JavaBeans.

POJO (Plain Old Java Object) to obiekt Java, który nie rozszerza ani nie implementuje niektórych wyspecjalizowanych klas i interfejsów wymaganych przez strukturę EJB. Wszystkie normalne obiekty Java to POJO.

Projektując klasę, która ma być utrwalana przez Hibernate, ważne jest zapewnienie kodu zgodnego z JavaBeans, a także jednego atrybutu, który działałby jak indeks id atrybut w klasie Employee.

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Utwórz tabele bazy danych

Drugim krokiem byłoby utworzenie tabel w bazie danych. Każdemu obiektowi odpowiadałaby jedna tabela, którą chcesz zapewnić trwałość. Rozważ powyższe obiekty, które należy przechowywać i pobierać do następującej tabeli RDBMS -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Utwórz plik konfiguracji odwzorowania

Ten krok polega na utworzeniu pliku mapowania, który instruuje Hibernate'a, jak odwzorować zdefiniowaną klasę lub klasy na tabele bazy danych.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Dokument odwzorowania należy zapisać w pliku w formacie <nazwaklasy> .hbm.xml. Zapisaliśmy nasz dokument mapowania w pliku Employee.hbm.xml. Zobaczmy trochę szczegółów na temat dokumentu mapowania -

  • Dokument mapowania jest dokumentem XML, którego głównym elementem jest <hibernate-mapping>, który zawiera wszystkie elementy <class>.

  • Plik <class>elementy służą do definiowania określonych mapowań z klas Java do tabel bazy danych. Nazwa klasy Java jest określana przy użyciu rozszerzenianame atrybut elementu klasy i nazwę tabeli bazy danych określa się za pomocą table atrybut.

  • Plik <meta> element jest elementem opcjonalnym i może służyć do tworzenia opisu klasy.

  • Plik <id>element odwzorowuje unikalny atrybut ID w klasie na klucz podstawowy tabeli bazy danych. Plikname atrybut elementu id odwołuje się do właściwości w klasie, a plik columnatrybut odnosi się do kolumny w tabeli bazy danych. Pliktype atrybut posiada typ odwzorowania hibernacji, te typy odwzorowania zostaną przekonwertowane z typu danych Java na SQL.

  • Plik <generator>element w elemencie id służy do automatycznego generowania wartości klucza podstawowego. Plikclass atrybut elementu generatora jest ustawiony na native niech hibernacja podniesie się identity, sequence lub hilo algorytm tworzenia klucza podstawowego w zależności od możliwości podstawowej bazy danych.

  • Plik <property>element służy do odwzorowania właściwości klasy Java na kolumnę w tabeli bazy danych. Plikname atrybut elementu odwołuje się do właściwości w klasie, a plik columnatrybut odnosi się do kolumny w tabeli bazy danych. Pliktype atrybut posiada typ odwzorowania hibernacji, te typy odwzorowania zostaną przekonwertowane z typu danych Java na SQL.

Dostępne są inne atrybuty i elementy, które zostaną użyte w dokumencie mapowania i spróbuję omówić jak najwięcej, omawiając inne tematy związane z Hibernate.

Utwórz klasę aplikacji

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main () do uruchamiania aplikacji. Użyjemy tej aplikacji do zapisania kilku rekordów pracownika, a następnie zastosujemy operacje CRUD na tych rekordach.

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee's records */
      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
      ME.listEmployees();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee(fname, lname, salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }
   
   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         List employees = session.createQuery("FROM Employee").list(); 
         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         employee.setSalary( salary );
		 session.update(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         session.delete(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik konfiguracyjny hibernate.cfg.xml zgodnie z opisem w rozdziale dotyczącym konfiguracji.

  • Utwórz plik mapowania Employee.hbm.xml, jak pokazano powyżej.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program.

Otrzymasz następujący wynik, a rekordy zostaną utworzone w tabeli EMPLOYEE.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000

Jeśli sprawdzisz swoją tabelę PRACOWNIK, powinna mieć następujące zapisy -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>

Do tej pory widzieliśmy bardzo podstawowe mapowanie O / R przy użyciu hibernacji, ale są trzy najważniejsze tematy mapowania, których musimy się szczegółowo nauczyć.

To są -

  • Mapowanie zbiorów,
  • Mapowanie skojarzeń między klasami jednostek i
  • Mapowania komponentów.

Mapowania kolekcji

Jeśli jednostka lub klasa ma kolekcję wartości dla określonej zmiennej, możemy zmapować te wartości za pomocą dowolnego z interfejsów kolekcji dostępnych w java. Hibernacja może utrzymywać wystąpieniajava.util.Map, java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, i jakikolwiek array trwałych bytów lub wartości.

Sr.No. Typ kolekcji i opis mapowania
1 java.util.Set

Jest to mapowane za pomocą elementu <set> i inicjowane za pomocą java.util.HashSet

2 java.util.SortedSet

Jest to mapowane za pomocą elementu <set> i inicjowane za pomocą java.util.TreeSet. Pliksort atrybut można ustawić na komparator lub porządek naturalny.

3 java.util.List

Jest to mapowane za pomocą elementu <list> i inicjowane za pomocą java.util.ArrayList

4 java.util.Collection

Jest to mapowane za pomocą elementu <bag> lub <ibag> i inicjowane za pomocą java.util.ArrayList

5 java.util.Map

Jest to mapowane za pomocą elementu <map> i inicjowane za pomocą java.util.HashMap

6 java.util.SortedMap

Jest to mapowane za pomocą elementu <map> i inicjowane za pomocą java.util.TreeMap. Pliksort atrybut można ustawić na komparator lub porządek naturalny.

Tablice są obsługiwane przez Hibernate z <primitive-array> dla pierwotnych typów wartości Java i <array> dla wszystkiego innego. Jednak są one rzadko używane, więc nie będę ich omawiać w tym tutorialu.

Jeśli chcesz zmapować interfejsy kolekcji zdefiniowane przez użytkownika, które nie są bezpośrednio obsługiwane przez Hibernate, musisz poinformować Hibernate o semantyce kolekcji niestandardowych, co nie jest łatwe i nie jest zalecane.

Mapowania skojarzeń

Odwzorowanie powiązań między klasami jednostek i relacjami między tabelami jest duszą ORM. Poniżej przedstawiono cztery sposoby wyrażenia mocy obliczeniowej relacji między obiektami. Mapowanie asocjacyjne może być zarówno jednokierunkowe, jak i dwukierunkowe.

Sr.No. Typ i opis mapowania
1 Wiele do jednego

Mapowanie relacji wiele do jednego za pomocą Hibernate

2 Jeden na jednego

Mapowanie relacji jeden do jednego za pomocą Hibernate

3 Jeden za dużo

Mapowanie relacji jeden-do-wielu za pomocą Hibernate

4 Wiele do wielu

Mapowanie relacji wiele-do-wielu przy użyciu Hibernate

Mapowania komponentów

Jest bardzo prawdopodobne, że klasa Entity może mieć odniesienie do innej klasy jako zmienna składowa. Jeśli klasa, o której mowa, nie ma własnego cyklu życia i całkowicie zależy od cyklu życia klasy jednostki będącej właścicielem, to klasa, do której odwołuje się, jest zatem nazywanaComponent class.

Mapowanie kolekcji składników jest również możliwe w podobny sposób, jak mapowanie zwykłych kolekcji z niewielkimi różnicami w konfiguracji. Zobaczymy szczegółowo te dwa mapowania wraz z przykładami.

Sr.No. Typ i opis mapowania
1 Mapowania komponentów

Mapowanie dla klasy mającej odwołanie do innej klasy jako zmiennej składowej.

Do tej pory widzieliście, jak Hibernate wykorzystuje plik mapowania XML do transformacji danych z POJO do tabel bazy danych i odwrotnie. Adnotacje Hibernacja to najnowszy sposób definiowania mapowań bez użycia pliku XML. Adnotacji można używać dodatkowo do metadanych mapowania XML lub w ich zastępstwie.

Hibernacja adnotacji to potężny sposób dostarczania metadanych dla mapowania obiektów i tabel relacyjnych. Wszystkie metadane są umieszczane w pliku POJO java wraz z kodem, co pomaga użytkownikowi zrozumieć strukturę tabeli i POJO jednocześnie podczas tworzenia.

Jeśli zamierzasz przenieść swoją aplikację do innych aplikacji ORM zgodnych z EJB 3, musisz użyć adnotacji do reprezentowania informacji o mapowaniu, ale nadal, jeśli chcesz większej elastyczności, powinieneś wybrać mapowania oparte na XML.

Konfiguracja środowiska dla adnotacji hibernacji

Przede wszystkim musisz się upewnić, że korzystasz z JDK 5.0, w przeciwnym razie musisz zaktualizować JDK do JDK 5.0, aby skorzystać z natywnej obsługi adnotacji.

Po drugie, musisz zainstalować pakiet dystrybucyjny adnotacji Hibernate 3.x, dostępny w sourceforge: ( Pobierz Hibernate Annotation ) i skopiujhibernate-annotations.jar, lib/hibernate-comons-annotations.jar i lib/ejb3-persistence.jar z dystrybucji Hibernate Annotations do CLASSPATH.

Przykład klasy z adnotacjami

Jak wspomniałem powyżej podczas pracy z Hibernate Annotation, wszystkie metadane są umieszczane w pliku POJO java wraz z kodem, co pomaga użytkownikowi zrozumieć strukturę tabeli i POJO jednocześnie podczas programowania.

Rozważmy, że będziemy używać następującej tabeli PRACOWNIK do przechowywania naszych obiektów -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Poniżej znajduje się mapowanie klasy Employee z adnotacjami do mapowania obiektów ze zdefiniowaną tabelą EMPLOYEE -

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
   @Id @GeneratedValue
   @Column(name = "id")
   private int id;

   @Column(name = "first_name")
   private String firstName;

   @Column(name = "last_name")
   private String lastName;

   @Column(name = "salary")
   private int salary;  

   public Employee() {}
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Hibernate wykrywa, że ​​adnotacja @Id znajduje się w polu i zakłada, że ​​powinna uzyskać dostęp do właściwości obiektu bezpośrednio przez pola w czasie wykonywania. Jeśli umieścisz adnotację @Id w metodzie getId (), domyślnie włączysz dostęp do właściwości za pośrednictwem metod pobierających i ustawiających. W związku z tym wszystkie inne adnotacje są również umieszczane na polach lub metodach pobierających, zgodnie z wybraną strategią.

Poniższa sekcja wyjaśni adnotacje użyte w powyższej klasie.

@Entity Adnotacja

Standardowe adnotacje EJB 3 są zawarte w javax.persistencepakiet, więc importujemy ten pakiet jako pierwszy krok. Po drugie, użyliśmy@Entity adnotacja do klasy Employee, która oznacza tę klasę jako komponent bean encji, więc musi mieć konstruktora bez argumentów, który jest widoczny z co najmniej chronionym zakresem.

@Table Adnotation

Adnotacja @Table umożliwia określenie szczegółów tabeli, która będzie używana do utrwalania jednostki w bazie danych.

Adnotacja @Table zawiera cztery atrybuty, które umożliwiają zastąpienie nazwy tabeli, jej katalogu i schematu oraz wymuszenie unikatowych ograniczeń na kolumnach w tabeli. Na razie używamy tylko nazwy tabeli, czyli PRACOWNIK.

@Id i @GeneratedValue Adnotations

Każdy komponent bean encji będzie miał klucz podstawowy, który można oznaczyć w klasie za pomocą @Idadnotacja. Klucz podstawowy może być pojedynczym polem lub kombinacją wielu pól, w zależności od struktury tabeli.

Domyślnie adnotacja @Id automatycznie określi najbardziej odpowiednią strategię generowania klucza podstawowego do użycia, ale możesz to zmienić, stosując @GeneratedValue adnotacja, która przyjmuje dwa parametry strategy i generatorktórych nie będę tutaj omawiać, więc użyjmy tylko domyślnej strategii generowania kluczy. Pozwalając Hibernate określić, jakiego typu generatora użyć, umożliwia przenoszenie kodu między różnymi bazami danych.

Adnotacja @Column

Adnotacja @Column służy do określenia szczegółów kolumny, do której zostanie zmapowane pole lub właściwość. Możesz użyć adnotacji kolumny z następującymi najczęściej używanymi atrybutami -

  • name atrybut umożliwia jawne określenie nazwy kolumny.

  • length atrybut zezwala na rozmiar kolumny używanej do mapowania wartości, szczególnie w przypadku wartości typu String.

  • nullable atrybut umożliwia oznaczenie kolumny jako NIE NULL podczas generowania schematu.

  • unique atrybut umożliwia oznaczenie kolumny jako zawierającej tylko unikalne wartości.

Utwórz klasę aplikacji

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main () do uruchamiania aplikacji. Użyjemy tej aplikacji do zapisania kilku rekordów pracownika, a następnie zastosujemy operacje CRUD na tych rekordach.

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new AnnotationConfiguration().
                   configure().
                   //addPackage("com.xyz") //add package if used.
                   addAnnotatedClass(Employee.class).
                   buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee's records */
      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
      ME.listEmployees();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee();
         employee.setFirstName(fname);
         employee.setLastName(lname);
         employee.setSalary(salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }
   
   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         List employees = session.createQuery("FROM Employee").list(); 
         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         employee.setSalary( salary );
		 session.update(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         session.delete(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Konfiguracja bazy danych

Teraz stwórzmy hibernate.cfg.xml plik konfiguracyjny do definiowania parametrów związanych z bazą danych.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>

      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         cohondob
      </property>

   </session-factory>
</hibernate-configuration>

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Usuń plik mapowania Employee.hbm.xml ze ścieżki.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program.

Otrzymasz następujący wynik, a rekordy zostaną utworzone w tabeli EMPLOYEE.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000

Jeśli sprawdzisz swoją tabelę PRACOWNIK, powinna mieć następujące zapisy -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>

Hibernate Query Language (HQL) jest zorientowanym obiektowo językiem zapytań, podobnym do SQL, ale zamiast operować na tabelach i kolumnach, HQL działa z obiektami trwałymi i ich właściwościami. Zapytania HQL są tłumaczone przez Hibernate na konwencjonalne zapytania SQL, które z kolei wykonują akcję na bazie danych.

Chociaż możesz używać instrukcji SQL bezpośrednio z Hibernate, używając Native SQL, ale zalecałbym używanie HQL, gdy tylko jest to możliwe, aby uniknąć problemów z przenoszeniem bazy danych i skorzystać ze strategii generowania SQL i buforowania Hibernate.

Słowa kluczowe takie jak SELECT, FROM i WHERE itp. Nie uwzględniają wielkości liter, ale we właściwościach, takich jak nazwy tabel i kolumn, w HQL rozróżniana jest wielkość liter.

Z klauzuli

Będziesz używać FROMklauzula, jeśli chcesz załadować kompletne trwałe obiekty do pamięci. Poniżej znajduje się prosta składnia użycia klauzuli FROM -

String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();

Jeśli chcesz w pełni zakwalifikować nazwę klasy w HQL, po prostu określ pakiet i nazwę klasy w następujący sposób -

String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();

Klauzula AS

Plik ASklauzula może służyć do przypisywania aliasów do klas w zapytaniach HQL, zwłaszcza w przypadku długich zapytań. Na przykład nasz poprzedni prosty przykład wyglądałby tak:

String hql = "FROM Employee AS E";
Query query = session.createQuery(hql);
List results = query.list();

Plik AS słowo kluczowe jest opcjonalne i możesz również określić alias bezpośrednio po nazwie klasy, w następujący sposób -

String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

Klauzula SELECT

Plik SELECTklauzula zapewnia większą kontrolę nad zestawem wyników niż klauzula from. Jeśli chcesz uzyskać kilka właściwości obiektów zamiast całego obiektu, użyj klauzuli SELECT. Poniżej znajduje się prosta składnia użycia klauzuli SELECT w celu uzyskania tylko pola first_name obiektu Employee -

String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

Jest to godne uwagi Employee.firstName jest właściwością obiektu Pracownik, a nie polem tabeli PRACOWNIK.

Klauzula GDZIE

Jeśli chcesz zawęzić określone obiekty zwracane z magazynu, użyj klauzuli WHERE. Poniżej znajduje się prosta składnia użycia klauzuli WHERE -

String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();

Klauzula ORDER BY

Aby posortować wyniki zapytania HQL, musisz użyć rozszerzenia ORDER BYklauzula. Wyniki można uporządkować według dowolnej właściwości obiektów w zestawie wyników rosnąco (ASC) lub malejąco (DESC). Poniżej znajduje się prosta składnia użycia klauzuli ORDER BY -

String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
Query query = session.createQuery(hql);
List results = query.list();

Jeśli chcesz sortować według więcej niż jednej właściwości, po prostu dodaj dodatkowe właściwości na końcu klauzuli order by, oddzielone przecinkami w następujący sposób -

String hql = "FROM Employee E WHERE E.id > 10 " +
             "ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();

Klauzula GROUP BY

Ta klauzula umożliwia Hibernate pobieranie informacji z bazy danych i grupowanie ich na podstawie wartości atrybutu oraz, zazwyczaj, wykorzystanie wyniku do uwzględnienia wartości zagregowanej. Poniżej znajduje się prosta składnia użycia klauzuli GROUP BY -

String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
             "GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();

Używanie nazwanych parametrów

Hibernate obsługuje nazwane parametry w zapytaniach HQL. To sprawia, że ​​pisanie zapytań HQL, które akceptują dane wejściowe od użytkownika, jest łatwe i nie musisz bronić się przed atakami typu SQL injection. Poniżej znajduje się prosta składnia używania nazwanych parametrów -

String hql = "FROM Employee E WHERE E.id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id",10);
List results = query.list();

Klauzula UPDATE

Aktualizacje zbiorcze są nowością w HQL z Hibernate 3, a usuwanie działa inaczej w Hibernate 3 niż w Hibernate 2. Interfejs Query zawiera teraz metodę o nazwie executeUpdate () do wykonywania instrukcji HQL UPDATE lub DELETE.

Plik UPDATEklauzula może służyć do aktualizowania jednej lub więcej właściwości jednego lub więcej obiektów. Poniżej znajduje się prosta składnia użycia klauzuli UPDATE -

String hql = "UPDATE Employee set salary = :salary "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

Klauzula DELETE

Plik DELETEklauzula może służyć do usuwania jednego lub więcej obiektów. Poniżej znajduje się prosta składnia użycia klauzuli DELETE -

String hql = "DELETE FROM Employee "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

Klauzula INSERT

Obsługa HQL INSERT INTOklauzula tylko wtedy, gdy rekordy mogą być wstawiane z jednego obiektu do drugiego. Poniżej znajduje się prosta składnia użycia klauzuli INSERT INTO -

String hql = "INSERT INTO Employee(firstName, lastName, salary)"  + 
             "SELECT firstName, lastName, salary FROM old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

Metody agregujące

HQL obsługuje szereg metod agregujących, podobnych do SQL. Działają tak samo w HQL, jak w SQL, a poniżej znajduje się lista dostępnych funkcji -

Sr.No. Funkcje i opis
1

avg(property name)

Średnia wartość nieruchomości

2

count(property name or *)

Liczba przypadków wystąpienia właściwości w wynikach

3

max(property name)

Maksymalna wartość wartości właściwości

4

min(property name)

Minimalna wartość wartości nieruchomości

5

sum(property name)

Suma wartości właściwości

Plik distinctsłowo kluczowe liczy tylko unikatowe wartości w zestawie wierszy. Następujące zapytanie zwróci tylko unikalną liczbę -

String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

Paginacja za pomocą zapytania

Istnieją dwie metody stronicowania interfejsu Query.

Sr.No. Metoda i opis
1

Query setFirstResult(int startPosition)

Ta metoda przyjmuje liczbę całkowitą reprezentującą pierwszy wiersz w zestawie wyników, zaczynając od wiersza 0.

2

Query setMaxResults(int maxResult)

Ta metoda nakazuje Hibernateowi pobranie ustalonej liczby maxResults obiektów.

Korzystając z powyższych dwóch metod razem, możemy zbudować komponent stronicowania w naszej aplikacji internetowej lub Swing. Oto przykład, który możesz rozszerzyć, aby pobrać 10 wierszy naraz -

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();

Hibernate zapewnia alternatywne sposoby manipulowania obiektami i danymi dostępnymi w tabelach RDBMS. Jedną z metod jest Criteria API, która umożliwia programowe tworzenie obiektu zapytania kryterialnego, w którym można zastosować reguły filtrowania i warunki logiczne.

Hibernate Session interfejs zapewnia createCriteria() , której można użyć do utworzenia pliku Criteria obiekt, który zwraca wystąpienia klasy obiektu trwałości, gdy aplikacja wykonuje zapytanie kryterium.

Poniżej znajduje się najprostszy przykład zapytania kryterialnego, które po prostu zwróci każdy obiekt odpowiadający klasie Employee.

Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();

Ograniczenia z kryteriami

Możesz użyć add() metoda dostępna dla Criteriaobiekt, aby dodać ograniczenie dla zapytania kryterialnego. Poniżej znajduje się przykład dodania ograniczenia zwrotu rekordów z wynagrodzeniem równym 2000 -

Criteria cr = session.createCriteria(Employee.class);
cr.add(Restrictions.eq("salary", 2000));
List results = cr.list();

Poniżej znajduje się kilka innych przykładów obejmujących różne scenariusze i można ich używać zgodnie z wymaganiami -

Criteria cr = session.createCriteria(Employee.class);

// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

// To get records having salary less than 2000
cr.add(Restrictions.lt("salary", 2000));

// To get records having fistName starting with zara
cr.add(Restrictions.like("firstName", "zara%"));

// Case sensitive form of the above restriction.
cr.add(Restrictions.ilike("firstName", "zara%"));

// To get records having salary in between 1000 and 2000
cr.add(Restrictions.between("salary", 1000, 2000));

// To check if the given property is null
cr.add(Restrictions.isNull("salary"));

// To check if the given property is not null
cr.add(Restrictions.isNotNull("salary"));

// To check if the given property is empty
cr.add(Restrictions.isEmpty("salary"));

// To check if the given property is not empty
cr.add(Restrictions.isNotEmpty("salary"));

Możesz tworzyć warunki AND lub OR przy użyciu ograniczeń LogicalExpression w następujący sposób -

Criteria cr = session.createCriteria(Employee.class);

Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");

// To get records matching with OR conditions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );

// To get records matching with AND conditions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );

List results = cr.list();

Chociaż wszystkie powyższe warunki mogą być używane bezpośrednio z HQL, jak wyjaśniono w poprzednim samouczku.

Paginacja za pomocą kryteriów

Istnieją dwie metody stronicowania za pomocą interfejsu Kryteria.

Sr.No. Metoda i opis
1

public Criteria setFirstResult(int firstResult)

Ta metoda przyjmuje liczbę całkowitą reprezentującą pierwszy wiersz w zestawie wyników, zaczynając od wiersza 0.

2

public Criteria setMaxResults(int maxResults)

Ta metoda nakazuje Hibernateowi pobranie ustalonej liczby maxResults obiektów.

Korzystając z powyższych dwóch metod razem, możemy zbudować komponent stronicowania w naszej aplikacji internetowej lub Swing. Oto przykład, który możesz rozszerzyć, aby pobrać 10 wierszy naraz -

Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(1);
cr.setMaxResults(10);
List results = cr.list();

Sortowanie wyników

Criteria API zapewnia org.hibernate.criterion.Orderklasy, aby posortować zestaw wyników w kolejności rosnącej lub malejącej, zgodnie z jedną z właściwości obiektu. Ten przykład pokazuje, jak można użyć klasy Order do sortowania zestawu wyników -

Criteria cr = session.createCriteria(Employee.class);

// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));

// To sort records in descening order
cr.addOrder(Order.desc("salary"));

// To sort records in ascending order
cr.addOrder(Order.asc("salary"));

List results = cr.list();

Prognozy i agregacje

Criteria API zapewnia org.hibernate.criterion.Projectionsklasa, której można użyć do uzyskania średniej, maksymalnej lub minimalnej wartości właściwości. Klasa Projections jest podobna do klasy Restrictions, ponieważ udostępnia kilka statycznych metod fabrycznych do uzyskiwaniaProjection instancje.

Poniżej znajduje się kilka przykładów obejmujących różne scenariusze i można ich używać zgodnie z wymaganiami -

Criteria cr = session.createCriteria(Employee.class);

// To get total row count.
cr.setProjection(Projections.rowCount());

// To get average of a property.
cr.setProjection(Projections.avg("salary"));

// To get distinct count of a property.
cr.setProjection(Projections.countDistinct("firstName"));

// To get maximum of a property.
cr.setProjection(Projections.max("salary"));

// To get minimum of a property.
cr.setProjection(Projections.min("salary"));

// To get sum of a property.
cr.setProjection(Projections.sum("salary"));

Kryteria Zapytania Przykład

Rozważ następującą klasę POJO -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Utwórzmy następującą tabelę EMPLOYEE do przechowywania obiektów Employee -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Poniżej znajduje się plik mapowania.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main (), aby uruchomić aplikację, której będziemy używać Criteria zapytania -

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Projections;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 5000);
      Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);

      /* List down all the employees */
      ME.listEmployees();

      /* Print Total employee's count */
      ME.countEmployee();

      /* Print Total salary */
      ME.totalSalary();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee(fname, lname, salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }

   /* Method to  READ all the employees having salary more than 2000 */
   public void listEmployees( ) {
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);
         // Add restriction.
         cr.add(Restrictions.gt("salary", 2000));
         List employees = cr.list();

         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to print total number of records */
   public void countEmployee(){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);

         // To get total row count.
         cr.setProjection(Projections.rowCount());
         List rowCount = cr.list();

         System.out.println("Total Coint: " + rowCount.get(0) );
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
  
   /* Method to print sum of salaries */
   public void totalSalary(){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Criteria cr = session.createCriteria(Employee.class);

         // To get total salary.
         cr.setProjection(Projections.sum("salary"));
         List totalSalary = cr.list();

         System.out.println("Total Salary: " + totalSalary.get(0) );
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik konfiguracyjny hibernate.cfg.xml zgodnie z opisem w rozdziale dotyczącym konfiguracji.

  • Utwórz plik mapowania Employee.hbm.xml, jak pokazano powyżej.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program.

Otrzymasz następujący wynik, a rekordy zostaną utworzone w tabeli EMPLOYEE.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
Total Coint: 4
Total Salary: 15000

Jeśli sprawdzisz swoją tabelę PRACOWNIK, powinna zawierać następujące zapisy:

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 14 | Zara       | Ali       |   2000 |
| 15 | Daisy      | Das       |   5000 |
| 16 | John       | Paul      |   5000 |
| 17 | Mohd       | Yasee     |   3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>

Możesz używać rodzimego języka SQL do wyrażania zapytań do bazy danych, jeśli chcesz korzystać z funkcji specyficznych dla bazy danych, takich jak wskazówki dotyczące zapytań lub słowo kluczowe CONNECT w Oracle. Hibernate 3.x umożliwia określenie odręcznego języka SQL, w tym procedur składowanych, dla wszystkich operacji tworzenia, aktualizacji, usuwania i ładowania.

Twoja aplikacja utworzy natywne zapytanie SQL z sesji z rozszerzeniem createSQLQuery() metoda w interfejsie sesji -

public SQLQuery createSQLQuery(String sqlString) throws HibernateException

Po przekazaniu ciągu znaków zawierającego zapytanie SQL do metody createSQLQuery () można powiązać wynik SQL z istniejącą jednostką Hibernate, złączeniem lub wynikiem skalarnym za pomocą metod addEntity (), addJoin () i addScalar () odpowiednio.

Zapytania skalarne

Najbardziej podstawowym zapytaniem SQL jest pobranie listy skalarów (wartości) z jednej lub wielu tabel. Poniżej znajduje się składnia używania natywnego języka SQL dla wartości skalarnych -

String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List results = query.list();

Zapytania o jednostki

Powyższe zapytania dotyczyły zwracania wartości skalarnych, w zasadzie zwracania „surowych” wartości ze zbioru wyników. Poniżej przedstawiono składnię służącą do pobierania obiektów encji jako całości z natywnego zapytania sql za pośrednictwem metody addEntity ().

String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list();

Nazwane zapytania SQL

Poniżej przedstawiono składnię służącą do pobierania obiektów encji z natywnego zapytania sql za pośrednictwem metody addEntity () i przy użyciu nazwanego zapytania SQL.

String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();

Przykład rodzimego języka SQL

Rozważ następującą klasę POJO -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Utwórzmy następującą tabelę EMPLOYEE do przechowywania obiektów Employee -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Następujący będzie plik mapowania -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main (), aby uruchomić aplikację, której będziemy używać Native SQL zapytania -

import java.util.*; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 5000);
      Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);

      /* List down employees and their salary using Scalar Query */
      ME.listEmployeesScalar();

      /* List down complete employees information using Entity Query */
      ME.listEmployeesEntity();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee(fname, lname, salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }

   /* Method to  READ all the employees using Scalar Query */
   public void listEmployeesScalar( ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         String sql = "SELECT first_name, salary FROM EMPLOYEE";
         SQLQuery query = session.createSQLQuery(sql);
         query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
         List data = query.list();

         for(Object object : data) {
            Map row = (Map)object;
            System.out.print("First Name: " + row.get("first_name")); 
            System.out.println(", Salary: " + row.get("salary")); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }

   /* Method to READ all the employees using Entity Query */
   public void listEmployeesEntity( ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         String sql = "SELECT * FROM EMPLOYEE";
         SQLQuery query = session.createSQLQuery(sql);
         query.addEntity(Employee.class);
         List employees = query.list();

         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik konfiguracyjny hibernate.cfg.xml zgodnie z opisem w rozdziale dotyczącym konfiguracji.

  • Utwórz plik mapowania Employee.hbm.xml, jak pokazano powyżej.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program.

Otrzymasz następujący wynik, a rekordy zostaną utworzone w tabeli EMPLOYEE.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara  Last Name: Ali  Salary: 2000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000

Jeśli sprawdzisz swoją tabelę PRACOWNIK, powinna mieć następujące zapisy -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 26 | Zara       | Ali       |   2000 |
| 27 | Daisy      | Das       |   5000 |
| 28 | John       | Paul      |   5000 |
| 29 | Mohd       | Yasee     |   3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>

Buforowanie to mechanizm zwiększający wydajność systemu. Jest to pamięć buforowa, która znajduje się między aplikacją a bazą danych. Pamięć podręczna przechowuje ostatnio używane elementy danych w celu jak największego zmniejszenia liczby trafień w bazie danych.

Buforowanie jest również ważne dla Hibernate. Wykorzystuje wielopoziomowy schemat buforowania, jak wyjaśniono poniżej -

Pamięć podręczna pierwszego poziomu

Pamięć podręczna pierwszego poziomu to pamięć podręczna sesji i jest to obowiązkowa pamięć podręczna, przez którą muszą przejść wszystkie żądania. Obiekt Session utrzymuje obiekt we własnym zakresie przed przekazaniem go do bazy danych.

Jeśli wydasz wiele aktualizacji obiektu, Hibernate próbuje opóźnić aktualizację tak długo, jak to możliwe, aby zmniejszyć liczbę wydawanych instrukcji SQL aktualizujących. Jeśli zamkniesz sesję, wszystkie buforowane obiekty zostaną utracone i zostaną utrwalone lub zaktualizowane w bazie danych.

Pamięć podręczna drugiego poziomu

Pamięć podręczna drugiego poziomu jest opcjonalną pamięcią podręczną, a pamięć podręczna pierwszego poziomu będzie zawsze sprawdzana przed podjęciem jakiejkolwiek próby zlokalizowania obiektu w pamięci podręcznej drugiego poziomu. Pamięć podręczna drugiego poziomu może być konfigurowana dla poszczególnych klas i kolekcji i jest głównie odpowiedzialna za buforowanie obiektów między sesjami.

W Hibernate można używać dowolnej pamięci podręcznej innej firmy. Naorg.hibernate.cache.CacheProvider interfejs, który należy zaimplementować, aby Hibernate miał dostęp do implementacji pamięci podręcznej.

Pamięć podręczna na poziomie zapytania

Hibernate implementuje również pamięć podręczną dla zestawów wyników zapytań, która jest ściśle zintegrowana z pamięcią podręczną drugiego poziomu.

Jest to funkcja opcjonalna i wymaga dwóch dodatkowych fizycznych regionów pamięci podręcznej, które przechowują buforowane wyniki zapytania i sygnatury czasowe ostatniej aktualizacji tabeli. Jest to przydatne tylko w przypadku zapytań, które są często uruchamiane z tymi samymi parametrami.

Pamięć podręczna drugiego poziomu

Hibernacja domyślnie używa pamięci podręcznej pierwszego poziomu i nie musisz nic robić, aby korzystać z pamięci podręcznej pierwszego poziomu. Przejdźmy od razu do opcjonalnej pamięci podręcznej drugiego poziomu. Nie wszystkie klasy korzystają z buforowania, dlatego ważne jest, aby móc wyłączyć pamięć podręczną drugiego poziomu.

Pamięć podręczna drugiego poziomu Hibernacji jest konfigurowana w dwóch krokach. Najpierw musisz zdecydować, której strategii współbieżności użyć. Następnie należy skonfigurować wygasanie pamięci podręcznej i atrybuty fizycznej pamięci podręcznej przy użyciu dostawcy pamięci podręcznej.

Strategie współbieżności

Strategia współbieżności to mediator, który jest odpowiedzialny za przechowywanie elementów danych w pamięci podręcznej i pobieranie ich z pamięci podręcznej. Jeśli zamierzasz włączyć pamięć podręczną drugiego poziomu, będziesz musiał zdecydować dla każdej trwałej klasy i kolekcji, której strategii współbieżności pamięci podręcznej użyć.

  • Transactional - Użyj tej strategii w przypadku danych głównie do odczytu, w przypadku których krytyczne jest zapobieganie przestarzałym danym w transakcjach współbieżnych, w rzadkich przypadkach aktualizacji.

  • Read-write - Ponownie użyj tej strategii dla danych głównie do odczytu, w przypadku których krytyczne jest zapobieganie przestarzałym danym w transakcjach współbieżnych, w rzadkich przypadkach aktualizacji.

  • Nonstrict-read-write- Ta strategia nie gwarantuje spójności między pamięcią podręczną a bazą danych. Skorzystaj z tej strategii, jeśli dane prawie nigdy się nie zmieniają, a małe prawdopodobieństwo nieaktualnych danych nie jest krytycznym problemem.

  • Read-only- Strategia współbieżności odpowiednia dla danych, które nigdy się nie zmieniają. Używaj go tylko do danych referencyjnych.

Jeśli zamierzamy używać buforowania drugiego poziomu dla naszego Employee dodajmy element mapujący wymagany do nakazania Hibernate buforowaniu instancji Employee przy użyciu strategii odczytu i zapisu.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <cache usage = "read-write"/>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Atrybut use = "odczyt-zapis" mówi Hibernate, aby użył strategii współbieżności odczytu i zapisu dla zdefiniowanej pamięci podręcznej.

Dostawca pamięci podręcznej

Następnym krokiem po rozważeniu strategii współbieżności będzie użycie klas kandydatów do pamięci podręcznej, aby wybrać dostawcę pamięci podręcznej. Hibernate zmusza Cię do wybrania jednego dostawcy pamięci podręcznej dla całej aplikacji.

Sr.No. Nazwa i opis pamięci podręcznej
1

EHCache

Może buforować w pamięci lub na dysku i buforować klastrowo i obsługuje opcjonalną pamięć podręczną wyników zapytań Hibernate.

2

OSCache

Obsługuje buforowanie pamięci i dysku w pojedynczej maszynie JVM z bogatym zestawem zasad wygasania ważności i obsługą pamięci podręcznej zapytań.

3

warmCache

Pamięć podręczna klastra oparta na JGroups. Używa unieważniania klastrowego, ale nie obsługuje pamięci podręcznej zapytań Hibernate.

4

JBoss Cache

W pełni transakcyjna replikowana klastrowana pamięć podręczna również oparta na bibliotece multiemisji JGroups. Obsługuje replikację lub unieważnianie, synchroniczną lub asynchroniczną komunikację oraz optymistyczne i pesymistyczne blokowanie. Obsługiwana jest pamięć podręczna zapytań Hibernate.

Każdy dostawca pamięci podręcznej nie jest zgodny z każdą strategią współbieżności. Poniższa tabela zgodności pomoże Ci wybrać odpowiednią kombinację.

Strategia / dostawca Tylko czytać Nonstrictread-write Odczyt i zapis Transakcyjne
EHCache X X X  
OSCache X X X  
SwarmCache X X    
JBoss Cache X     X

Dostawcę pamięci podręcznej określisz w pliku konfiguracyjnym hibernate.cfg.xml. Wybieramy EHCache jako dostawcę pamięci podręcznej drugiego poziomu -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>
   
      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         root123
      </property>
   
      <property name = "hibernate.cache.provider_class">
         org.hibernate.cache.EhCacheProvider
      </property>
   
      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>
   
   </session-factory>
</hibernate-configuration>

Teraz musisz określić właściwości regionów pamięci podręcznej. EHCache ma własny plik konfiguracyjny,ehcache.xml, który powinien znajdować się w CLASSPATH aplikacji. Konfiguracja pamięci podręcznej w ehcache.xml dla klasy Employee może wyglądać następująco -

<diskStore path="java.io.tmpdir"/>

<defaultCache
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
/>

<cache name = "Employee"
maxElementsInMemory = "500"
eternal = "true"
timeToIdleSeconds = "0"
timeToLiveSeconds = "0"
overflowToDisk = "false"
/>

To wszystko, teraz mamy włączone buforowanie drugiego poziomu dla klasy Pracownik i Hibernacja, teraz trafia do pamięci podręcznej drugiego poziomu za każdym razem, gdy nawigujesz do pracownika lub gdy ładujesz pracownika według identyfikatora.

Powinieneś przeanalizować wszystkie swoje klasy i wybrać odpowiednią strategię buforowania dla każdej z nich. Czasami buforowanie drugiego poziomu może obniżyć wydajność aplikacji. Dlatego zaleca się najpierw wykonać test porównawczy aplikacji, bez włączania buforowania, a później włączyć dobrze dopasowane buforowanie i sprawdzić wydajność. Jeśli buforowanie nie poprawia wydajności systemu, nie ma sensu włączać żadnego typu buforowania.

Pamięć podręczna na poziomie zapytania

Aby użyć pamięci podręcznej zapytań, musisz ją najpierw aktywować przy użyciu pliku hibernate.cache.use_query_cache="true"właściwość w pliku konfiguracyjnym. Ustawiając tę ​​właściwość na true, sprawisz, że Hibernate utworzy w pamięci niezbędne bufory do przechowywania zapytań i zestawów identyfikatorów.

Następnie, aby użyć pamięci podręcznej zapytań, należy użyć metody setCacheable (Boolean) klasy Query. Na przykład -

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();

Hibernate obsługuje również bardzo precyzyjną obsługę pamięci podręcznej poprzez koncepcję regionu pamięci podręcznej. Region pamięci podręcznej jest częścią pamięci podręcznej, której nadano nazwę.

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();

Ten kod używa metody, aby nakazać Hibernate przechowywanie i wyszukiwanie zapytania w obszarze pracownika pamięci podręcznej.

Rozważ sytuację, w której musisz przesłać dużą liczbę rekordów do swojej bazy danych za pomocą Hibernacji. Poniżej znajduje się fragment kodu umożliwiający osiągnięcie tego za pomocą Hibernate -

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
}
tx.commit();
session.close();

Domyślnie Hibernate buforuje wszystkie utrwalone obiekty w pamięci podręcznej na poziomie sesji i ostatecznie aplikacja przewróci się z OutOfMemoryExceptiongdzieś w okolicach 50-tysięcznego rzędu. Możesz rozwiązać ten problem, jeśli używaszbatch processing z Hibernate.

Aby użyć funkcji przetwarzania wsadowego, najpierw ustaw hibernate.jdbc.batch_sizejako wielkość partii do liczby 20 lub 50 w zależności od wielkości obiektu. To powie kontenerowi hibernacji, że każde X wierszy ma być wstawione jako partia. Aby zaimplementować to w swoim kodzie, musielibyśmy dokonać niewielkiej modyfikacji w następujący sposób -

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
   if( i % 50 == 0 ) { // Same as the JDBC batch size
      //flush a batch of inserts and release memory:
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Powyższy kod będzie działał dobrze dla operacji INSERT, ale jeśli chcesz wykonać operację UPDATE, możesz to osiągnąć za pomocą następującego kodu -

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE").scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee); 
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Przykład przetwarzania wsadowego

Zmodyfikujmy plik konfiguracyjny, aby dodać hibernate.jdbc.batch_size nieruchomość -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>

      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         root123
      </property>
   
      <property name = "hibernate.jdbc.batch_size">
         50
      </property>

      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>

   </session-factory>
</hibernate-configuration>

Rozważ następującą klasę pracownika POJO -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Utwórzmy następującą tabelę EMPLOYEE do przechowywania obiektów Employee -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Poniżej znajduje się plik mapowania do mapowania obiektów pracownika z tabelą EMPLOYEE -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main (), aby uruchomić aplikację, której będziemy używać flush() i clear() metody dostępne z obiektem Session, dzięki czemu Hibernate zapisuje te rekordy w bazie danych zamiast buforować je w pamięci.

import java.util.*; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      ManageEmployee ME = new ManageEmployee();

      /* Add employee records in batches */
      ME.addEmployees( );
   }
   
   /* Method to create employee records in batches */
   public void addEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         for ( int i=0; i<100000; i++ ) {
            String fname = "First Name " + i;
            String lname = "Last Name " + i;
            Integer salary = i;
            Employee employee = new Employee(fname, lname, salary);
            session.save(employee);
         	if( i % 50 == 0 ) {
               session.flush();
               session.clear();
            }
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return ;
   }
}

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik konfiguracyjny hibernate.cfg.xml, jak wyjaśniono powyżej.

  • Utwórz plik mapowania Employee.hbm.xml, jak pokazano powyżej.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program, który utworzy 100000 rekordów w tabeli EMPLOYEE.

Jak się dowiedziałeś, że w Hibernate obiekt zostanie utworzony i utrwalony. Po zmianie obiektu należy go ponownie zapisać w bazie danych. Ten proces jest kontynuowany do następnego razu, gdy obiekt będzie potrzebny i zostanie załadowany z magazynu trwałego.

W ten sposób obiekt przechodzi przez różne etapy swojego cyklu życia i Interceptor Interfaceudostępnia metody, które można wywołać na różnych etapach w celu wykonania niektórych wymaganych zadań. Metody te to wywołania zwrotne z sesji do aplikacji, umożliwiające aplikacji przeglądanie i / lub manipulowanie właściwościami trwałego obiektu przed jego zapisaniem, aktualizacją, usunięciem lub załadowaniem. Poniżej znajduje się lista wszystkich metod dostępnych w interfejsie Interceptora -

Sr.No. Metoda i opis
1

findDirty()

Ta metoda jest wywoływana, gdy flush() metoda jest wywoływana w obiekcie Session.

2

instantiate()

Ta metoda jest wywoływana podczas tworzenia wystąpienia klasy utrwalonej.

3

isUnsaved()

Ta metoda jest wywoływana, gdy obiekt jest przesyłany do saveOrUpdate() metoda/

4

onDelete()

Ta metoda jest wywoływana przed usunięciem obiektu.

5

onFlushDirty()

Ta metoda jest wywoływana, gdy Hibernate wykryje, że obiekt jest zabrudzony (tj. Został zmieniony) podczas operacji opróżniania, czyli aktualizacji.

6

onLoad()

Ta metoda jest wywoływana przed zainicjowaniem obiektu.

7

onSave()

Ta metoda jest wywoływana przed zapisaniem obiektu.

8

postFlush()

Ta metoda jest wywoływana po wystąpieniu opróżnienia i zaktualizowaniu obiektu w pamięci.

9

preFlush()

Ta metoda jest wywoływana przed flush.

Hibernate Interceptor daje nam pełną kontrolę nad wyglądem obiektu zarówno w aplikacji, jak iw bazie danych.

Jak używać przechwytywaczy?

Aby zbudować przechwytywacz, możesz zaimplementować Interceptor klasę bezpośrednio lub rozszerz EmptyInterceptorklasa. Poniżej przedstawiono proste kroki korzystania z funkcji Hibernate Interceptor.

Utwórz przechwytywacze

W naszym przykładzie rozszerzymy EmptyInterceptor, w którym metoda Interceptora zostanie wywołana automatycznie when Employeeobiekt jest tworzony i aktualizowany. Możesz wdrożyć więcej metod zgodnie ze swoimi wymaganiami.

import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;

import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;

public class MyInterceptor extends EmptyInterceptor {
   private int updates;
   private int creates;
   private int loads;

   public void onDelete(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
       // do nothing
   }

   // This method is called when Employee object gets updated.
   public boolean onFlushDirty(Object entity, Serializable id,
      Object[] currentState, Object[] previousState, String[] propertyNames,
      Type[] types) {
         if ( entity instanceof Employee ) {
            System.out.println("Update Operation");
            return true; 
         }
         return false;
   }
	
   public boolean onLoad(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
         // do nothing
         return true;
   }
   
   // This method is called when Employee object gets created.
   public boolean onSave(Object entity, Serializable id,
      Object[] state, String[] propertyNames, Type[] types) {
         if ( entity instanceof Employee ) {
            System.out.println("Create Operation");
            return true; 
         }
         return false;
   }
   
   //called before commit into database
   public void preFlush(Iterator iterator) {
      System.out.println("preFlush");
   }
   
   //called after committed into database
   public void postFlush(Iterator iterator) {
      System.out.println("postFlush");
   }
}

Utwórz klasy POJO

Teraz zmodyfikujmy trochę nasz pierwszy przykład, w którym użyliśmy tabeli EMPLOYEE i klasy Employee do zabawy -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Utwórz tabele bazy danych

Drugim krokiem byłoby utworzenie tabel w bazie danych. Każdemu obiektowi odpowiadałaby jedna tabela, którą chcesz zapewnić trwałość. Rozważ obiekty wyjaśnione powyżej, należy je przechowywać i pobierać do następującej tabeli RDBMS -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Utwórz plik konfiguracji odwzorowania

Ten krok polega na utworzeniu pliku mapowania, który instruuje Hibernate - jak odwzorować zdefiniowaną klasę lub klasy na tabele bazy danych.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Utwórz klasę aplikacji

Na koniec utworzymy naszą klasę aplikacji za pomocą metody main () do uruchamiania aplikacji. W tym miejscu należy zauważyć, że podczas tworzenia obiektu sesji użyliśmy naszej klasy Interceptor jako argumentu.

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }

      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee's records */
      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
      ME.listEmployees();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession( new MyInterceptor() );
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee(fname, lname, salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }
   
   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.openSession( new MyInterceptor() );
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         List employees = session.createQuery("FROM Employee").list(); 
         for (Iterator iterator = employees.iterator(); iterator.hasNext();){
            Employee employee = (Employee) iterator.next(); 
            System.out.print("First Name: " + employee.getFirstName()); 
            System.out.print("  Last Name: " + employee.getLastName()); 
            System.out.println("  Salary: " + employee.getSalary()); 
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession( new MyInterceptor() );
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         employee.setSalary( salary );
		 session.update(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
   
   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession( new MyInterceptor() );
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = (Employee)session.get(Employee.class, EmployeeID); 
         session.delete(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Kompilacja i wykonanie

Oto kroki, aby skompilować i uruchomić wyżej wymienioną aplikację. Upewnij się, że odpowiednio ustawiłeś PATH i CLASSPATH przed przystąpieniem do kompilacji i wykonania.

  • Utwórz plik konfiguracyjny hibernate.cfg.xml zgodnie z opisem w rozdziale dotyczącym konfiguracji.

  • Utwórz plik mapowania Employee.hbm.xml, jak pokazano powyżej.

  • Utwórz plik źródłowy Employee.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy MyInterceptor.java, jak pokazano powyżej, i skompiluj go.

  • Utwórz plik źródłowy ManageEmployee.java, jak pokazano powyżej, i skompiluj go.

  • Uruchom plik binarny ManageEmployee, aby uruchomić program.

Otrzymasz następujący wynik, a rekordy zostaną utworzone w tabeli EMPLOYEE.

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush

Jeśli sprawdzisz swoją tabelę PRACOWNIK, powinna mieć następujące zapisy -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>