Dlaczego warto używać JPA zamiast pisać zapytanie SQL przy użyciu JDBC?

Czytałem kilka artykułów Co to jest JPA (Java Persistent API) i który dostawca go obsługujący (DataNucleus, JBoss Hibernate itp.)

Nie mam doświadczenia z ORM (object relational mapping).

To, co dotychczas zrobiłem, to pisanie własnych klas bazodanowych przy użyciu DTO i DAO. Jak na razie jestem zadowolony z tego, co mam, ale chciałbym wiedzieć Dlaczego ludzie używają JPA zamiast Pliku Java, który zawiera SQL .

Dla mnie czuję, że pisanie zajęć DAO byłoby ok coś jak poniżej.

public class DAOUsers {
     public void insertNewUser(DTO DtoUser) {
           String query = "INSERT INTO users(username, address) " +
                          "VALUES(DtoUser.username , DtoUser.address)";
           Executor.run(query);
     }

}

Nauczyłem się, że JPA używa JPQL, Java persistent Query language i działa przeciwko obiektowi encji zamiast bezpośrednio z tabelami db.

Moje zrozumienie (popraw mnie, jeśli się mylę) czy ten obiekt encji jest taki sam jak mój obiekt DTO (coś jak bean?)

Ale tak czy inaczej.. jakie naprawdę korzyści daje JPA przy pisaniu czystego SQL w moim pliku? Wygląda na to, że używanie adnotacji wymaganych przez JPA i uczynienie SQL nieczytelnym wydaje się niezbyt atrakcyjne dla ja..

Proszę dać mi znać, jeśli potrzebujesz więcej wyjaśnień, jestem nowy w tym temacie i chciałbym usłyszeć jakąś opinię.

Author: Vlad Mihalcea, 2010-12-10

9 answers

Dlaczego używać JPA zamiast bezpośrednio zapisanie zapytania SQL na pliku Java (tj. bezpośrednio do JDBC)?

Niektóre projekty wymagają od inżynierów skupienia się bardziej na modelu obiektowym niż na rzeczywistych zapytaniach SQL używanych do uzyskiwania dostępu do magazynów danych. Pytanie może być interpretowane jako

Dlaczego warto używać frameworka ORM ?

Które mogą mieć różne odpowiedzi w różnych kontekstach.

Większość projektów może skorzystać z posiadania domeny model, z uporem jest drugim problemem. W przypadku implementacji JPA lub większości innych frameworków ORM możliwe jest posiadanie w bazie danych wszystkich encji tj. tabel, modelowanych jako klasy w Javie. Dodatkowo, możliwe jest również osadzenie zachowania w tych klasach, a tym samym osiągnięcie behawioralnie bogatego modelu domeny. Podmioty w tym modelu mogą mieć wiele celów, w tym celu zastąpienie Dto do przesyłania danych między warstwami.

To powiedziawszy, są miejsca gdzie frameworki ORM mogą nie być bezpośrednio dopasowane do problemu, zwłaszcza gdy model danych jest już ustanowiony, lub gdy pracuje się z systemami starszymi, gdzie mapowanie tabel baz danych do klas Java jest nietrywialnym ćwiczeniem. W niektórych przypadkach, jeśli trzeba absolutnie dostroić SQL generowany przez framework ORM, to frameworki ORM są zwykle źle dopasowane.

Powiązane Pytania

  1. Architektura Java EE-czy DAO wciąż zalecane podczas korzystania z ORM jak JPA 2?
  2. używając ORM czy zwykłego SQL?
  3. ORM vs Handcoded Data Access Layer
 48
Author: Vineet Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:15

Jakie korzyści daje JPA przy pisaniu czystego SQL w moim pliku?

Oto niektóre z korzyści:

  • JPA pozwala uniknąć pisania DDL w specyficznym dialekcie bazy danych SQL. Zamiast tego piszesz "mappings" w XML lub używając adnotacji Java.

  • JPA pozwala uniknąć pisania DML w specyficznym dialekcie bazy danych SQL.

  • JPA pozwala ładować i zapisywać obiekty i wykresy Javy bez żadnego języka DML w wszystkie.

  • Kiedy robisz potrzebujesz wykonywać zapytania JPQL pozwala wyrazić zapytania w kategoriach encji Java, a nie (natywnych) tabel i kolumn SQL.

Ogólnie rzecz biorąc, JPA jest prostsze, czystsze i mniej pracochłonne niż JDBC + SQL + ręcznie pisane mapowania. Im bardziej skomplikowany model danych, tym bardziej korzystny.

Jeśli jednak wydajność jest problemem nadrzędnym , JPA ma tendencję do wchodzenia w drogę poprzez dodawanie warstw między aplikacją a bazą danych. Jeśli Twoja aplikacja wymaga intensywnej ręcznej optymalizacji natywnych zapytań i schematów bazy danych, aby zmaksymalizować wydajność, JPA prawdopodobnie nie pasuje.

JPA prawdopodobnie nie jest również dla Ciebie, jeśli są o wiele wygodniejsze żonglowanie Java, JDBC i SQL w tej samej aplikacji, niż pozwalając ORM zajmować się brudnymi szczegółami. (Ale jeśli jesteś, prawdopodobnie jesteś w mniejszości ...)

 25
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 22:47:19

Chociaż to stare pytanie, uważam, że zasługuje na nową odpowiedź. Jestem późnym użytkownikiem JPA, używam go i wyłączam od kilku lat i chociaż miałem chwile, gdy byłem pod wrażeniem prostoty stawiania nowej aplikacji, stałem się zdecydowanie nie pod wrażeniem wydajności, złożoności i krzywej uczenia wymaganej do poprawnego wykonywania JPA. Odpowiedzi w tym wątku faktycznie wzmacniają moją pozycję.

Po pierwsze, @vineet sugeruje " byty mogą mieć wiele celów"... który widziałem w produkcji i powiedziałbym, że jest zachęcany przez ORM. To tyle, jeśli chodzi o spójność i podstawową odpowiedzialność. Z mojego doświadczenia wynika, że dodawanie zachowań do jednostek bazodanowych wymaga kłopotów. Wiem to, bo to zrobiłem i żyłem, żeby tego żałować.

Po drugie, istnieją proste alternatywy dla złożoności JPA, które zapewniają możliwość korzystania z klas z RDBMS bez wszystkich ciężkości (i problemów z wydajnością) spowodowanych niedopasowaniem, które ORM próbuje (bezskutecznie) rozwiązać. Od dekady używamy narzędzi mapowania klas relacyjnych innych niż JPA w aplikacji z ponad 1000 tabelami i po prostu nie widzimy, jak JPA jest ulepszeniem w stosunku do bardziej bezpośredniego dostępu do bazy danych. JPA zasłania moc bazy danych podczas dodawania napowietrznych (w postaci adnotacji i JQL) do modelu klasy... nie powinno działać w drugą stronę?

@water sugeruje wiele rzeczy, które są prawdziwe w teorii, ale niepraktyczne w rzeczywistości. Na przykład, po trzykrotnym przełączeniu baz danych backendowych mogę zapewnić czytelników, że nie ma czegoś takiego jak kilka poprawek konfiguracyjnych i gotowe. Sugerowałbym, że jeśli spędzasz dużo czasu na utrzymaniu warstwy trwałości, twój model bazy danych ewoluuje i wykonujesz tę samą lub większą pracę w JPA. Szczególnie, gdy nie trywialne zapytania w JPA wymagają użycia JQL!

Prawie każdy udaje, że programiści JPA nie muszą znać SQL. To, co widziałem w praktyce, to to, że teraz musimy poznaj SQL i JQL. Najwyraźniej nie musimy robić DDL - ale w każdej Nie trywialnej aplikacji oczywiście musisz znać DDL. Hibernate nie zaleca nawet automatycznego generowania DDL. Najwyraźniej nie musimy robić DML, z wyjątkiem sytuacji, gdy wywołujemy natywne zapytanie, które oczywiście nie jest przenośne, rozwala pamięć podręczną i ma te same problemy co JDBC...

Ostatecznie, w odpowiednio skonstruowanej aplikacji, gdzie model domeny jest niezależny od biznesu logika, JPA zapewnia niewiele funkcjonalności w stosunku do tego, co uznałem za bardzo wysoką krzywą uczenia się-ponieważ model domeny jest w rzeczywistości bardzo łatwy do zbudowania. Nie używałbym JDBC bezpośrednio, ale coś takiego jak Apache DBUtils zapewnia prostą warstwę nad JDBC, która mapuje wiersze do obiektów i przy odrobinie wysiłku może zapewnić większość zalet JPA bez ukrywania i bez narzutów.

Zajmuję się tworzeniem aplikacji bazodanowych Java od JDBC 1.0, używając różnorodność bibliotek (iodbc i ESQL przed JDBC), i tylko ze względów wydajnościowych skończyłem z JPA. Ale nawet jeśli wydajność była lepsza, krzywa uczenia się i niepełne abstrakcje dają mi poważną pauzę. JPA jest złożona i stara się ukryć szczegóły, na których, moim zdaniem, deweloperzy rzeczywiście muszą dbać. Jako przykład, niedawno widzieliśmy hibernate wydanie 250 poleceń delete do bazy danych, gdy jeden wystarczy. JPA ze swej natury ułatwia tego rodzaju błędy.

Nie jestem opowiadam się za JDBC, po prostu opowiadam się przeciwko JPA. Programiści, którzy nie pracują lub nie mogą pracować w SQL, nie powinni pisać aplikacji relacyjnych - tak samo jak Programiści tacy jak ja, którzy nie potrafili zrobić algebry macierzy, aby uratować mi życie, powinni pisać gry 3D. Programiści, którzy używają SQL do życia, powinni być przerażeni zniekształconym SQL, który hibernuje, na przykład, wysyła do serwera, aby uniknąć podróży w obie strony, które nie powinny być konieczne w pierwszej kolejności.

 25
Author: Doctor Eval,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-23 10:14:39

JDBC jest verbose

Na przykład, jest to najczęstszy sposób wstawiania niektórych rekordów:

int postCount = 100;

try (PreparedStatement postStatement = connection.prepareStatement("""
    INSERT INTO post (
        id,
        title 
    ) 
    VALUES (
        ?, 
        ?
    )
    """
)) {
    for (int i = 1; i <= postCount; i++) {        
        int index = 0;
        
        postStatement.setLong(
            ++index, 
            i
        );
        postStatement.setString(
            ++index, 
            String.format(
                "High-Performance Java Persistence, review no. %1$d", 
                i
            )
        );
        
        postStatement.executeUpdate();
    }
} catch (SQLException e) {
    fail(e.getMessage());
}

JDBC batching wymaga zmiany kodu dostępu do danych

I w momencie, gdy zdałeś sobie sprawę, że to nie działa dobrze, ponieważ zapomniałeś użyć batchingu, musisz zmienić poprzednią implementację, Tak:

int postCount = 100;
int batchSize = 50;

try (PreparedStatement postStatement = connection.prepareStatement("""
    INSERT INTO post (
        id,
        title 
    ) 
    VALUES (
        ?, 
        ?
    )
    """
)) {
    for (int i = 1; i <= postCount; i++) {
        if (i % batchSize == 0) {
            postStatement.executeBatch();
        }
        
        int index = 0;
        
        postStatement.setLong(
            ++index, 
            i
        );
        postStatement.setString(
            ++index, 
            String.format(
                "High-Performance Java Persistence, review no. %1$d", 
                i
            )
        );
        
        postStatement.addBatch();
    }
    postStatement.executeBatch();
} catch (SQLException e) {
    fail(e.getMessage());
}

JPA i alternatywa Hibernate

Z JPA, po zmapowaniu swojej jednostki:

@Entity
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    public Long getId() {
        return id;
    }

    public Post setId(Long id) {
        this.id = id;
        return this;
    }

    public String getTitle() {
        return title;
    }

    public Post setTitle(String title) {
        this.title = title;
        return this;
    }
}

I ustawiasz następujące Właściwość konfiguracji Hibernate:

<property name="hibernate.jdbc.batch_size" value="50"/>

Tak można wstawić te post rekordy tabeli:

for (long i = 1; i <= postCount; i++) {
    entityManager.persist(
        new Post()
            .setId(i)
            .setTitle(
                String.format(
                    "High-Performance Java Persistence, review no. %1$d", 
                    i
                )
            )
    );
}
Dużo prostsze, prawda?

Pobieranie danych za pomocą JDBC

Z JDBC, tak wykonujesz projekcję SQL:

int maxResults = 10;

List<Post> posts = new ArrayList<>();

try (PreparedStatement preparedStatement = connection.prepareStatement("""
        SELECT 
            p.id AS id, 
            p.title AS title
        FROM post p 
        ORDER BY p.id
        LIMIT ?
        """
)) {
    preparedStatement.setInt(1, maxResults);

    try (ResultSet resultSet = preparedStatement.executeQuery()) {
        while (resultSet.next()) {
            int index = 0;
            
            posts.add(
                new Post()
                    .setId(resultSet.getLong(++index))
                    .setTitle(resultSet.getString(++index))
            );
        }
    }

} catch (SQLException e) {
    fail(e.getMessage());
}

Jest to dość gadatliwe, ponieważ musisz przekształcić ResultSet do struktury danych, której używa Twoja aplikacja (np. dtos, JSON Web response).

Pobieranie danych za pomocą JPA

Z JPA możesz pobrać List z Post zapisy takie jak:

int maxResults = 10;

List<Post> posts = entityManager.createQuery("""
    select p
    from post p 
    order by p.id
    """, Post.class)
.setMaxResults(maxResults)
.getResultList();

I nie tylko, że łatwiej jest go napisać, ale działa on na każdej bazie danych obsługiwanej przez Hibernate, ponieważ składnia paginacji jest dostosowana w oparciu o dialekt bazodanowy.

Inne zalety JPA nad JDBC

  • możesz pobrać encje lub DTOs. Możesz nawet pobrać hierarchiczną projekcję DTO rodzic-dziecko.
  • możesz włączyć grupowanie JDBC bez zmiany kodu dostępu do danych.
  • masz wsparcie do blokowania optymistycznego.
  • masz pesymistyczną abstrakcję blokowania, która jest niezależna od podstawowej składni specyficznej dla bazy danych, dzięki czemu możesz uzyskać blokadę odczytu i zapisu lub nawet blokadę pomijania .
  • masz niezależne od bazy danych API paginacji.
  • hibernate.query.in_clause_parameter_padding.
  • możesz użyć silnie spójnego rozwiązania buforowania, które pozwala odciążyć węzeł główny, który w przypadku transakcji odczytu i zapisu może być wywoływany tylko pionowo.
  • masz wbudowaną obsługę rejestrowania audytu przez Hibernate Envers.
  • W tym celu należy skontaktować się z działem obsługi klienta.
  • możesz wygenerować początkowy skrypt schematu z mapowania encji za pomocą narzędzia Hibernate hbm2ddl, które możesz dostarczyć do automatycznego narzędzia do migracji schematu, takiego jak Flyway.
  • nie tylko, że masz swobodę wykonywania dowolnych natywnych zapytań SQL , ale możesz użyć Sqlresultsetmapping do przekształcenia JDBC ResultSet w encje JPA lub DTOs.

Wady JPA

Wady używania JPA i Hibernate są następujące:

  • podczas gdy rozpoczęcie pracy z JPA jest bardzo łatwe, zostań ekspertem wymaga znacznych nakładów czasu, ponieważ oprócz czytania jego podręcznika, nadal musisz nauczyć się, jak działają systemy bazodanowe, standard SQL, a także specyficzny smak SQL używany przez twoją relację z projektem baza danych.
  • istnieją mniej intuicyjne zachowania, które mogą zaskoczyć początkujących, takie jak kolejność operacji flush .
  • Criteria API jest dość obszerne, więc musisz użyć narzędzia takiego jak Codota , aby łatwiej pisać dynamiczne zapytania.

Podsumowanie

Jedną z największych zalet ekosystemu Javy jest bogactwo wysokiej jakości frameworków. Jeśli JPA i Hibernate nie pasują do twojego przypadku użycia, możesz użyć dowolnego z następujące frameworki:

  • [107]}MyBatis, który jest bardzo lekkim frameworkiem SQL query mapper.
  • Pozwala na dynamiczne budowanie zapytań SQL, JPA, Lucene i MongoDB.
  • jOOQ , który dostarcza metamodel Java dla bazowych tabel, procedur składowanych i funkcji oraz pozwala na dynamiczne budowanie zapytania SQL przy użyciu bardzo intuicyjnego DSL i w sposób bezpieczny dla typu.

Podczas gdy JPA przynosi wiele zalet, masz wiele innych wysokiej jakości alternatyw do użycia, jeśli JPA i Hibernate nie działają najlepiej dla obecnych wymagań aplikacji. Tak więc w dzisiejszych czasach nie musisz używać zwykłego JDBC, chyba że opracowujesz Framework dostępu do danych.

 14
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-09 17:22:24

Jeśli zostanie wykonana poprawnie, można mapować zapytania SQL bezpośrednio do obiektów java za pomocą implementacji JPA, takich jak hibernate. Niedawno zrobiłem projekt, w którym miałem POJO i 3 lub 4 adnotacje i trochę kodu konfiguracji, aby wziąć procedurę składowaną i mapować ją bezpośrednio do listy obiektów(typu klasy POJO). Dla mnie to część mocy JPA.

Jeśli używasz go tak, jak byś prosto SQL+JDBC to nie znam żadnych zalet.

Jest porządny artykuł tutaj {[6] } o zaletach JPA.

Mam nadzieję, że to pomoże.

 6
Author: javamonkey79,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 06:42:34

Jak wszyscy wiemy, obiekt jest jedną z najważniejszych rzeczy w naszym życiu i w programowaniu obiekt jest bardzo łatwym sposobem na uproszczenie każdego problemu.... a jeśli obiekt jest tam Dostępny, to dlaczego używamy całości zamiast tej małej części tej rzeczy oznacza obiekt....

  • jeśli ręcznie kodujesz polecenia SQL w swojej aplikacji korporacyjnej wydają znaczną ilość twój czas rozwoju aktualizacji i utrzymanie warstwy trwałości.

In persistance,= = > nie ma potrzeby używania interfejsów API JDBC do obsługi zestawów wyników lub danych. = = > Pomaga zredukować linie kodu, &&&&&& = = > Abstrahuje naszą aplikację od baz danych SQL i dialektu sql. Przejście do innej bazy danych SQL wymaga kilku zmian w pliku konfiguracyjnym Hibernate (zapis raz / uruchom w dowolnym miejscu).

 6
Author: Ravi Parmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 06:47:04
  • JPA jest idealnym rozwiązaniem dla złożonych aplikacji nie zorientowanych na wydajność.
  • JDBC jest najlepszym rozwiązaniem, gdzie wydajność jest kluczowym wykonawcą.
 4
Author: Shreyu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 07:25:24

DODATKOWO, jak wiecie hasło Javy: "Pisz raz, biegaj wszędzie"

Również z JPQL możesz wykonywać swoje zapytania JPQL na każdej bazie danych (DB2, Oracle, itp..)

 0
Author: yetAnotherSE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-01 14:46:46

Przy użyciu JDBC mamy jedną warstwę mapowania do mapowania tabel połączonych DB do obiektu biznesowego. Jednak JPA w ten czy inny sposób wymusza, aby obiekty danych utrzymywały się osobno, co dodatkowo utrudnia utrzymanie i refaktoryzację tabel DB.

Zgadzam się również z https://stackoverflow.com/a/57766861/3343801

 0
Author: Venkateswara Rao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-26 16:22:13