Hibernate

Hibernate

Hibernate is an open source object relational mapping (ORM) tool that provides a framework to map object-oriented domain models to relational databases for web applications.

The Support Of Spring Data JPA for Loading Relational Data

Spring Data is an additional layer above common technologies for storing data. Spring Data JPA, the most commonly used part of Spring Data, is supposed to simplify JPA-based code by eliminating recurrent pieces of code. Essentially Spring Data JPA is a kind of JPA with hidden EntityManager.

In this post, I want to explore the support of Spring Data JPA for loading relational data. Spring Data JPA, by default, depends on Hibernate. Since some of Spring Data JPA limitations are caused by Hibernate, I additionally assess Spring Data JPA with a more powerful JPA implementation EclipseLink.

I compare several ways of loading data from the tiny Sakila sample schema of MySQL database. To compare approaches:

  • I count the number of executed SQL queries. By default, JPA implementations execute one query per each parent entity.
  • I measure the time needed to load the data. The time depends on the number of unnecessary selects.
  • I check if the loaded data is correctly converted into entities.
  • I check the data is correctly sorted. Hibernate is known to mess up the order in the loaded relational data, but it is interesting to know if findAll(Sort) is compatible with relational data.

See more at: https://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48

#hibernate #spring 

The Support Of Spring Data JPA for Loading Relational Data

Le Support De Spring Data JPA Pour Le Chargement Des Données Relationn

Spring Data est une couche supplémentaire au-dessus des technologies courantes de stockage de données. Spring Data JPA, la partie la plus couramment utilisée de Spring Data, est censée simplifier le code basé sur JPA en éliminant les morceaux de code récurrents. Spring Data JPA est essentiellement une sorte de JPA avec caché EntityManager.

Dans cet article, je souhaite explorer la prise en charge de Spring Data JPA pour le chargement de données relationnelles. Spring Data JPA, par défaut, dépend de Hibernate. Étant donné que certaines des limitations de Spring Data JPA sont causées par Hibernate, j'évalue en outre Spring Data JPA avec une implémentation JPA plus puissante, EclipseLink.

Je compare plusieurs façons de charger des données à partir du petit exemple de schéma Sakila de la base de données MySQL. Pour comparer les approches :

  • Je compte le nombre de requêtes SQL exécutées. Par défaut, les implémentations JPA exécutent une requête pour chaque entité parent.
  • Je mesure le temps nécessaire pour charger les données. Le temps dépend du nombre de selects inutiles.
  • Je vérifie si les données chargées sont correctement converties en entités.
  • Je vérifie que les données sont correctement triées. Hibernate est connu pour perturber l'ordre dans les données relationnelles chargées, mais il est intéressant de savoir s'il findAll(Sort)est compatible avec les données relationnelles.

ActorDans mes expériences , j'utilise trois classes Filmet Categorymappées à cinq tables de l'exemple de schéma Sakila :

Le diagramme des relations signifie qu'un acteur peut jouer dans de nombreux films et que chaque film peut inclure de nombreux acteurs. Les mêmes catégories sont réutilisées pour classer les films. Chaque film peut appartenir à plusieurs catégories. Les données comprennent 200 acteurs, 1000 films et 16 catégories. Je charge les données avec trois entités :

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

Les tables contiennent plus de colonnes que je n'en charge. Pour la simplicité du code, je charge uniquement les colonnes les plus significatives.

Notez également une limitation insensée d'Hibernate. Avec un select, les associations imbriquées ne peuvent être chargées que dans Sets. Cette aberration n'existe pas dans EclipseLink. Donc, avec EclipseLink, je stocke les entités liées dans Lists. Contrairement à Sets, Lists préserve l'ordre des données chargées et permet un accès simple à leurs éléments avec la méthode get().

Plusieurs approches différentes pour charger tous les acteurs avec des films et des catégories associés

Tout d'abord, comme résultat de départ et de référence, j'utiliserai un code purement basé sur JDBC. Ensuite, j'évalue les findAll()et les findAll(Sort)méthodes de JpaRepository. Pour montrer que certaines des aberrations produites par les référentiels se produisent parce que Spring Data JPA dépend d'une version obsolète d'Hibernate, je compare l'Hibernate 5.6.9 utilisé par Spring Data à l'Hibernate 6 moderne. Ensuite, j'évalue deux méthodes décorées avec @Querydes annotations. Enfin, je montre que les méthodes de référentiel attrayantes telles que findByFirstName()génèrent de nombreuses requêtes inutiles.

Voici les résultats numériques :

Hiberner

EclipseLink

Il existe certaines similitudes entre Hibernate et EclipseLink. Si vous regardez la ligne intitulée rep.query(), vous voyez qu'une requête JPQL est suffisante pour charger toutes les données. findAll()produit beaucoup de requêtes inutiles et est donc lent. findAll(Sort)renvoie en outre un nombre anormal d'acteurs. Fondamentalement, quelle que soit l'implémentation JPA sous-jacente, les deux méthodes d' JpaRepositoryinterface ne sont pas très utiles pour les données relationnelles.

Je montre l'ordre des données chargées et discute des résultats numériques plus en détail ci-dessous. Mais avant cela, je dois expliquer comment je les ai collectés pour qu'ils aient l'air crédibles.

Mesure du temps d'exécution de la méthode et comptage des sélections exécutées par Hibernate ou EclipseLink

Dans les applications Web, les données sont généralement chargées pour être affichées. Pour être affichées, les données doivent être complètement chargées. JPA charge les associations plusieurs-à-plusieurs paresseusement, c'est-à-dire progressivement lorsqu'elles sont accessibles. Pour comparer les temps nécessaires pour charger les données complètes, mon code de benchmarking accède à toutes les catégories imbriquées dans tous les acteurs chargés.

Il existe plusieurs façons délicates de compter le nombre de selects pour la plupart inutiles. J'ai utilisé le plus simple. J'ai activé la journalisation Hibernate ou EclipseLink en ajoutant spring.jpa.properties.hibernate.show_sql=trueou spring.jpa.properties.eclipselink.logging.level=FINE, respectivement, à application.properties . Ensuite, je compte simplement dans la sortie standard les lignes qui commencent par Hibernate: selectou [EL Fine]: sql: SELECT.

Le code mesure 15 fois le temps d'exécution de chaque approche. Mais seules les 10 dernières mesures sont utilisées pour compter le temps moyen. Le code est simple mais trop long pour paraître lisible ici. Vous pouvez le voir dans le GitHub .

Chargement de données relationnelles avec JDBC pur

Par rapport au code dépendant de couches supplémentaires telles que JPA, le code JDBC pur présente un avantage : une fois développé, ses tests n'échoueront pas lorsque l'une des dépendances sera mise à niveau.

Avec JDBC, toutes les données peuvent être chargées avec une seule requête SQL :

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

Remarque, je souhaite que les données soient triées par nom d'acteur, titre de film et enfin nom de catégorie. Si JDBC ou EclipseLink est utilisé, cela peut être réalisé avec order byla clause.

Il existe de nombreuses façons de décomposer un produit de jointure en entités associées. Cela peut être fait très facilement avec des flux Java. Le code devient encore plus simple avec un collecteur générique personnalisé. Vous pouvez voir le code dans le GitHub . Je ne le montre pas ici car le code est encore relativement long et, comme vous le voyez dans les résultats de l'analyse comparative, il n'est pas beaucoup plus rapide que le code analogue basé sur JPA. Les flux sont pratiques mais sont associés à de nombreux codes auxiliaires génériques et sont donc lents.

Les premières lignes des données chargées et correctement triées :

Peu importe pour cet article, mais notez que, bien que le schéma comprenne une relation plusieurs à plusieurs entre les films et les catégories, aucun des films de la base de données Sakila n'est associé à plus d'une catégorie.

En raison d'un nombre déraisonnable de sélections, findAll() est lent

Normalement, findAll()of JpaRepositoryne doit être utilisé qu'avec des entités sans relations. Si les entités chargées ont des associations, findAll()cela peut entraîner le blocage de l'application. Dans mon expérience avec des données irréalistes, la findAll()méthode n'a besoin que d'environ 4 fois plus de temps que l'approche JDBC ou JPA. L'essentiel de son temps d'exécution est consacré à l'exécution de 1198 selects (1 selectpour charger les acteurs, 200 selects pour charger les films et 997 selects pour charger les catégories). Si la base de données contenait une quantité de données plus réaliste ou si la base de données n'était pas sur l' hôte local, le temps d'exécution serait beaucoup plus long. Les requêtes graduelles inutiles ne sont pas un problème de Spring Data, c'est une fonctionnalité bizarre de JPA - une requête est exécutée pour chaque entité parent.

findAll(Sort) ne trie pas et renvoie trop

Je suppose qu'il est rarement acceptable de charger des données non triées comme les données renvoyées par le fichier findAll(). Même si les données doivent être triées dans le navigateur en réponse à l'entrée de l'utilisateur, pour le premier rendu, il est agréable d'avoir des données triées. Les référentiels Spring Data proposent une méthode findAll(Sort)censée récupérer des données triées. En termes de temps d'exécution, il est aussi inefficace que findAll(). Étrangement, il en retourne un Listavec 5462 acteurs au lieu des 200 attendus.

Je mon code la méthode est invoquée avec:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

Il trie avec succès les auteurs par leur nom et prénom mais ne peut pas trier les films par leur titre.

Ce problème est causé par Hibernate, car avec EclipseLink l'ordre est correct :

Modern Hibernate traite de manière incorrecte les jointures de récupération

Avant de discuter des résultats obtenus avec les requêtes JPQL, je dois démontrer une différence importante entre le Hibernate 6 moderne et le Hibernate 5 obsolète utilisé par Spring Data. Hibernate 6 est incompatible avec Spring Data et à peine compatible avec Spring.

JPA peut parfois certainement simplifier le code. Tous les auteurs peuvent être chargés avec une requête JPQL plus courte que la requête SQL équivalente ci-dessus. Le code pour charger tous les acteurs est beaucoup plus court que le code basé sur JDBC.

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

Hibernate n'offre aucun autre moyen de charger efficacement les entités associées, à l'exception des fetch joins . Malheureusement, le même code produit des résultats différents avec Hibernate 6 et Hibernate 5.

Vous voyez dans le tableau de résultats ci-dessus que l'hibernate obsolète utilisé par Spring Data en utilise un selectpour charger toutes les données, il est aussi rapide que le code JDBC, mais il renvoie un Listavec 5462 acteurs au lieu de 200. C'est une fonctionnalité de JPA -selon Selon la spécification JPA, les jointures d'extraction doivent produire autant de résultats que de jointures.

En revanche, Hibernate 6 renvoie le nombre correct d'acteurs. C'est pratique et correct selon le bon sens, mais selon la spécification JPA, c'est incorrect.

Aucune des deux versions d'Hibernate ne conserve l'ordre défini par la order byclause.

Pourquoi utiliser des interfaces de référentiel pour exécuter des requêtes JPQL

Il est possible d'utiliser des interfaces de référentiel pour exécuter des requêtes JPQL. Dans les référentiels, les requêtes peuvent être spécifiées avec @Querydes annotations.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

Le code ne semble pas être plus court que le code équivalent basé sur JPA ci-dessus. Elle produit le même aberrant Listavec 5462 acteurs que l'approche JPA ci-dessus.

Les jointures de récupération imbriquées ne sont pas prises en charge par EclipseLink, mais des conseils de requête peuvent être utilisés à la place. Avec EclipseLink, les résultats sont bien meilleurs — 200 acteurs correctement triés. Voyons s'il y a beaucoup de différence entre le code JPA :

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

et le code Spring Data JPA équivalent :

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

Bien sûr, contrairement à Hibernate, EclipseLink renvoie des données bien ordonnées :

Il ne semble donc pas que Spring Data JPA simplifie le code avec les requêtes JPQL. Il est inutile d'utiliser Spring Data JPA avec des requêtes JPQL.

Comment utiliser les jointures de récupération avec Spring Data JPA

Jusqu'à ce que Spring Data JPA commence à prendre en charge une mise en veille prolongée plus moderne, les résultats aberrants des jointures de récupération peuvent être améliorés en ajoutant un mot-clé distinctà la requête JPQL.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

Maintenant, la requête produit le nombre attendu d'entités. Mais comme prévu pour Hibernate, ils ne sont pas correctement triés.

Méthodes de requête attrayantes mais inefficaces

La dernière ligne de mon tableau de résultats numériques sert simplement à noter que les méthodes de requête ont un prix - elles produisent beaucoup de selects graduels inutiles qui prennent du temps.

conclusion

Si vous savez comment l'utiliser, JPA peut simplifier le code et n'est pas beaucoup plus lent que JDBC pur. Spring aide à gérer les transactions. Spring Data JPA est une couche supplémentaire au-dessus de JPA et Spring. Ce que cela apporte n'est pas très clair, à l'exception d'une manière sophistiquée de définir des requêtes inefficaces avec des noms de méthode dans les interfaces.

Les interfaces de référentiel peuvent avoir deux types de méthodes — les méthodes dont les noms définissent les requêtes JPQL (par exemple findByFirstName()) et les méthodes renvoyant les résultats des requêtes JPQL spécifiées avec une @Queryannotation.

Il n'est pas évident lorsqu'une base de données H2 en mémoire avec peu de données est utilisée, mais les méthodes sophistiquées d'interfaces de référentiel ont un prix - elles sont extrêmement lentes. Si vous utilisez des bases de données relationnelles pour stocker des données relationnelles, les méthodes de requête par nom inefficaces ne peuvent pas remplacer les requêtes JPQL.

Mais il est inutile d'utiliser une dépendance Spring Data JPA supplémentaire pour exécuter des requêtes JPQL. Le code équivalent sans Spring Data JPA n'est pas plus long et peut utiliser des EntityManagerméthodes parfois indispensables telles que detach()ou persist()auxquelles manquent les interfaces de référentiel.

Certains des problèmes de Spring Data JPA sont causés par les limitations d'Hibernate. Lorsqu'il est utilisé avec des données relationnelles, Hibernate ne conserve pas l'ordre défini par la order byclause dans les requêtes JPQL. Par conséquent, la méthode inefficace findAll(Sort)ne trie pas à moins que Hibernate soit remplacé par EclipseLink. Il est étrange que Spring Data JPA dépende de l'implémentation de JPA qui ne semble pas entièrement compatible avec les méthodes fournies par Spring Data JPA.

Dans l'ensemble, Spring Data JPA convient mieux aux applications de démonstration avec des bases de données vides. 

Source : https://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48 

#hibernate #spring

Le Support De Spring Data JPA Pour Le Chargement Des Données Relationn
坂本  健一

坂本 健一

1661173500

リレーショナル データをロードするための Spring Data JPA のサポート

Spring Data は、データを保存するための一般的なテクノロジーの上にある追加のレイヤーです。Spring Data の最も一般的に使用される部分である Spring Data JPA は、繰り返し発生するコードを排除することで、JPA ベースのコードを簡素化することになっています。基本的に Spring Data JPA は hidden を持つ JPA の一種ですEntityManager

この投稿では、リレーショナル データをロードするための Spring Data JPA のサポートについて調べたいと思います。デフォルトでは、Spring Data JPA は Hibernate に依存します。Spring Data JPA の制限の一部は Hibernate によって引き起こされるため、より強力な JPA 実装の EclipseLink を使用して Spring Data JPA をさらに評価します。

MySQL データベースの小さな Sakila サンプル スキーマからデータをロードするいくつかの方法を比較します。アプローチを比較するには:

  • 実行された SQL クエリの数をカウントします。デフォルトでは、JPA 実装は親エンティティごとに 1 つのクエリを実行します。
  • データのロードに必要な時間を測定します。時間は、不要なselectの数によって異なります。
  • 読み込まれたデータが正しくエンティティに変換されているかどうかを確認します。
  • データが正しくソートされていることを確認します。Hibernate はロードされたリレーショナル データの順序をめちゃくちゃにすることが知られていますが、findAll(Sort)リレーショナル データと互換性があるかどうかを知ることは興味深いことです。

私の実験では、3 つのクラスを使用Actorし、Sakila サンプル スキーマの 5 つのテーブルにマッピングしましたFilmCategory

関係図は、1 人の俳優が多くの映画に出演でき、各映画には多くの俳優が含まれることを意味します。映画を分類するために同じカテゴリが再利用されます。各映画は多くのカテゴリに属する​​ことができます。データには、200 人の俳優、1000 本の映画、16 のカテゴリが含まれています。次の 3 つのエンティティを使用してデータを読み込みます。

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

テーブルには、ロードしたよりも多くの列が含まれています。コードを簡潔にするために、最も意味のある列のみをロードします。

また、Hibernate の無意味な制限にも注意してください。oneselectでは、ネストされたアソシエーションは にのみロードできますSet。この異常は、EclipseLink には存在しません。したがって、EclipseLink では、関連するエンティティをLists に格納します。とは異なりSetListはロードされたデータの順序を保持し、メソッドを使用してそれらの要素に簡単にアクセスできますget()

関連する映画とカテゴリを持つすべての俳優をロードするためのいくつかの異なるアプローチ

まず、開始および参照結果として、純粋な JDBC ベースのコードを使用します。次に、findAll()とのfindAll(Sort)メソッドを評価しますJpaRepository。Spring Data JPA が廃止されたバージョンの Hibernate に依存しているために、リポジトリによって生成される異常の一部が発生することを示すために、Spring Data で使用される Hibernate 5.6.9 を最新の Hibernate 6 と比較します。次に、@Queryアノテーションで装飾された 2 つのメソッドを評価します。findByFirstName()最後に、多くの不要なクエリを生成するなどの見栄えの良いリポジトリ メソッドを示します。

数値結果は次のとおりです。

休止状態

EclipseLink

Hibernate と EclipseLink にはいくつかの類似点があります。というラベルの付いた行を見るとrep.query()、すべてのデータをロードするには 1 つの JPQL クエリで十分であることがわかります。findAll()多くの不要なクエリを生成するため、低速です。findAll(Sort)さらに異常な数のアクターを返します。基本的に、基盤となる JPA 実装に関係なく、JpaRepositoryインターフェースの両方のメソッドはリレーショナル データにはあまり役に立ちません。

読み込まれたデータの順序を示し、数値結果について以下で詳しく説明します。しかしその前に、信頼できるようにそれらをどのように収集したかを説明する必要があります。

メソッドの実行時間の測定と、Hibernate または EclipseLink によって実行された選択のカウント

Web アプリケーションでは、通常、データをロードして表示します。表示するには、データを完全にロードする必要があります。JPA は、多対多の関連付けを遅延して読み込みます。つまり、アクセスが徐々に行われます。完全なデータをロードするのに必要な時間を比較するために、私のベンチマーク コードは、ロードされたすべてのアクターのすべてのネストされたカテゴリにアクセスします。

ほとんど不要な の数を数えるには、いくつかのトリッキーな方法がありますselect。私は最も簡単なものを使用しました。spring.jpa.properties.hibernate.show_sql=trueまたはspring.jpa.properties.eclipselink.logging.level=FINEをそれぞれapplication.propertiesに追加して、Hibernate または EclipseLink のロギングをオンにしました。Hibernate: select次に、標準出力でorで始まる行を数えるだけ[EL Fine]: sql: SELECTです。

このコードは、各アプローチの実行時間を 15 回測定します。ただし、平均時間をカウントするために使用されるのは、最後の 10 回の測定値のみです。コードは単純ですが、長すぎて判読できません。GitHubで見ることができます。

純粋な JDBC を使用したリレーショナル データの読み込み

JPA などの追加レイヤーに依存するコードと比較して、純粋な JDBC コードには利点があります。一度開発すると、依存関係がアップグレードされてもテストが失敗することはありません。

JDBC を使用すると、すべてのデータを 1 つの SQL クエリでロードできます。

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

データを俳優名、映画のタイトル、最後にカテゴリ名で並べ替えることに注意してください。order byJDBC または EclipseLink を使用する場合、これは句で実現できます。

結合積を関連付けられたエンティティに分解する方法は多数あります。Java ストリームを使用すると、非常に便利に実行できます。カスタム汎用コレクターを使用すると、コードはさらに簡単になります。コードはGitHubで確認できます。コードはまだ比較的長く、ベンチマーク結果でわかるように、類似の JPA ベースのコードよりもそれほど高速ではないため、ここでは示しません。ストリームは便利ですが、多くの一般的な補助コードに関連付けられているため、低速です。

ロードされ、適切にソートされたデータの最初の行:

この投稿には関係ありませんが、スキーマには映画とカテゴリ間の多対多の関係が含まれていますが、Sakila データベース内のどの映画も複数のカテゴリに関連付けられていないことに注意してください。

選択数が不当なため、findAll() が遅い

通常findAll()、 ofJpaRepositoryは関係のないエンティティでのみ使用する必要があります。読み込まれたエンティティに関連付けがfindAll()ある場合、アプリケーションが正常にハングする可能性があります。非現実的なほど小さなデータを使用した私の実験では、findAll()メソッドは JDBC または JPA アプローチよりも最大 4 倍の時間を必要とします。selectその実行時間のほとんどは、1198秒の実行に費やされます (select俳優のロードに 1 秒、映画のロードに 200秒、カテゴリのロードselectに 997秒)。selectデータベースにもっと現実的な量のデータが含まれている場合、またはデータベースがローカルホスト上にない場合、実行時間ははるかに長くなります。不要な段階的クエリは Spring Data の問題ではなく、JPA の奇妙な機能です。親エンティティごとに 1 つのクエリが実行されます。

findAll(Sort) はソートされず、返される量が多すぎます

非効率的な によって返されるデータのように、ソートされていないデータをロードすることはめったに受け入れられないと思いますfindAll()。ユーザー入力に応じてブラウザーでデータを並べ替える場合でも、最初のレンダリングでは、データを並べ替えると便利です。Spring Data リポジトリは、findAll(Sort)ソートされたデータを取得することになっているメソッドを提供します。実行時間に関しては、 と同じくらい非効率的findAll()です。奇妙なことにList、予想される 200 ではなく、5462 のアクターを含む が返されます。

メソッドが呼び出される私のコード:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

著者を苗字と名前でソートすることはできますが、映画をタイトルでソートすることはできません。

EclipseLink では順序が正しいため、この問題は Hibernate によって引き起こされます。

最新の Hibernate がフェッチ結合を正しく処理しない

JPQL クエリで得られた結果について説明する前に、Spring Data で使用されている最新の Hibernate 6 と廃止された Hibernate 5 の重要な違いを示す必要があります。Hibernate 6 は Spring Data と互換性がなく、Spring とほとんど互換性がありません。

JPA は確かにコードを簡素化できる場合があります。すべての作成者は、上記の同等の SQL クエリよりも短い 1 つの JPQL クエリで読み込むことができます。すべてのアクターをロードするためのコードは、JDBC ベースのコードよりもはるかに短くなります。

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

Hibernate は、関連するエンティティを効率的にロードする方法をfetch join以外に提供していません。残念ながら、同じコードでも Hibernate 6 と Hibernate 5 では異なる結果が生成されます。

上記の結果テーブルでわかるように、Spring Data で使用される廃止された Hibernate は 1 つを使用selectしてすべてのデータをロードします。これは JDBC コードと同じくらい高速ですがList、200 ではなく 5462 のアクターで a を返します。これは JPA の機能です。 JPA 仕様では、フェッチ結合は結合と同じ数の結果を生成する必要があります。

対照的に、Hibernate 6 は正しい数のアクターを返します。常識的には便利で正しいですが、JPA の仕様からすると正しくありません。

Hibernate のどちらのバージョンも、order by句によって設定された順序を保持しません。

リポジトリ インターフェースを使用して JPQL クエリを実行する理由

リポジトリ インターフェイスを使用して JPQL クエリを実行できます。リポジトリでは、@Queryアノテーションを使用してクエリを指定できます。

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

このコードは、上記の同等の JPA ベースのコードよりも短くないようです。List上記の JPA アプローチと同様に、5462 アクターで同じ異常が発生します。

ネストされたフェッチ結合は EclipseLink ではサポートされていませんが、代わりにクエリ ヒントを使用できます。EclipseLink を使用すると、結果ははるかに良くなり、200 のアクターが適切にソートされます。JPA コードに大きな違いがあるかどうかを見てみましょう。

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

および同等の Spring Data JPA コード:

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

もちろん、Hibernate とは異なり、EclipseLink は適切に順序付けられたデータを返します。

そのため、Spring Data JPA が JPQL クエリを使用してコードを簡素化しているようには見えません。JPQL クエリで Spring Data JPA を使用しても意味がありません。

Spring Data JPA でフェッチ結合を使用する方法

Spring Data JPA が最新の Hibernate のサポートを開始するまでは、JPQL クエリにキーワードを追加することで、フェッチ結合の異常な結果を改善できます。distinct

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

これで、クエリは予想される数のエンティティを生成します。しかし、Hibernate で予想されるように、それらは適切にソートされていません。

見栄えは良いが非効率的な Query メソッド

select数値結果テーブルの最後の行は、クエリ メソッドには代償が伴うことを示しているだけです。クエリ メソッドは、時間がかかる不要な gradual を大量に生成します。

結論

使い方を知っていれば、JPA はコードを単純化でき、純粋な JDBC よりもそれほど遅くはありません。Spring は、トランザクションを処理するのに役立ちます。Spring Data JPA は、JPA と Spring の上にある追加のレイヤーです。インターフェイスでメソッド名を使用して非効率的なクエリを定義するという派手な方法を除いて、それが何をもたらすかはあまり明確ではありません。

findByFirstName()リポジトリ インターフェースは、名前が JPQL クエリを定義するメソッド (例: ) と、アノテーションで指定された JPQL クエリの結果を返すメソッドの 2 種類のメソッドを持つことができます@Query

データがほとんどないインメモリ H2 データベースが使用されている場合は明らかではありませんが、リポジトリ インターフェースの派手な方法には代償が伴います。リレーショナル データの格納にリレーショナル データベースを使用する場合、効率の悪い名前でクエリを実行する方法では、JPQL クエリを置き換えることはできません。

しかし、JPQL クエリを実行するために追加の Spring Data JPA 依存関係を使用しても意味がありません。Spring Data JPA を使用しない同等のコードはもはや存在せず、リポジトリ インターフェイスが欠落している、または欠落しているEntityManagerなどの不可欠なメソッドを使用できます。detach()persist()

Spring Data JPA の問題のいくつかは、Hibernate の制限によって引き起こされます。order byリレーショナル データで使用する場合、Hibernate はJPQL クエリの句によって設定された順序を保持しません。したがって、findAll(Sort)Hibernate が EclipseLink に置き換えられない限り、非効率的な方法はソートされません。Spring Data JPA が、Spring Data JPA によって提供されたメソッドと完全に互換性がないように見える JPA 実装に依存しているのは奇妙です。

全体として、Spring Data JPA は、空のデータベースを使用するデモ アプリケーションに最適です。 

ソース: https://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48 

#hibernate #spring

リレーショナル データをロードするための Spring Data JPA のサポート

O Suporte Do Spring Data JPA Para Carregar Dados Relacionais

Spring Data é uma camada adicional acima das tecnologias comuns para armazenamento de dados. Spring Data JPA, a parte mais comumente usada do Spring Data, deve simplificar o código baseado em JPA, eliminando partes de código recorrentes. Essencialmente, o Spring Data JPA é um tipo de JPA com arquivos EntityManager.

Neste post, quero explorar o suporte do Spring Data JPA para carregar dados relacionais. O Spring Data JPA, por padrão, depende do Hibernate. Como algumas das limitações do Spring Data JPA são causadas pelo Hibernate, também avalio o Spring Data JPA com uma implementação de JPA mais poderosa EclipseLink.

Eu comparo várias maneiras de carregar dados do pequeno esquema de amostra Sakila do banco de dados MySQL. Para comparar abordagens:

  • Eu conto o número de consultas SQL executadas. Por padrão, as implementações de JPA executam uma consulta por cada entidade pai.
  • Meço o tempo necessário para carregar os dados. O tempo depende do número de selects desnecessários.
  • Eu verifico se os dados carregados estão corretamente convertidos em entidades.
  • Verifico se os dados estão ordenados corretamente. O Hibernate é conhecido por atrapalhar a ordem nos dados relacionais carregados, mas é interessante saber se findAll(Sort)é compatível com os dados relacionais.

Em meus experimentos, uso três classes Actore mapeei Filmpara Categorycinco tabelas do esquema de amostra Sakila:

O diagrama de relacionamento significa que um ator pode atuar em muitos filmes, e cada filme pode incluir muitos atores. As mesmas categorias são reutilizadas para classificar os filmes. Cada filme pode pertencer a muitas categorias. Os dados incluem 200 atores, 1000 filmes e 16 categorias. Carrego os dados com três entidades:

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

As tabelas contêm mais colunas do que carrego. Para simplificar o código, carrego apenas as colunas mais significativas.

Observe também uma limitação sem sentido do Hibernate. Com um select, associações aninhadas podem ser carregadas apenas em Sets. Esta aberração não existe no EclipseLink. Assim, com EclipseLink, armazeno entidades relacionadas em Lists. Ao contrário Setde s, Lists preserva a ordem dos dados carregados e permite acesso simples aos seus elementos com o método get().

Várias abordagens diferentes para carregar todos os atores com filmes e categorias associadas

Primeiro, como resultado inicial e de referência, usarei um código baseado em JDBC puro. Então eu avalio os métodos findAll()e de . Para mostrar que algumas das aberrações produzidas pelos repositórios acontecem porque o Spring Data JPA depende de uma versão obsoleta do Hibernate, comparo o Hibernate 5.6.9 usado pelo Spring Data com o moderno Hibernate 6. Em seguida, avalio dois métodos decorados com anotação. Por fim, mostro que métodos de repositório de boa aparência, como gerar muitas consultas dispensáveis.findAll(Sort)JpaRepository@QueryfindByFirstName()

Aqui estão os resultados numéricos:

Hibernar

EclipseLink

Existem algumas semelhanças entre o Hibernate e o EclipseLink. Se você observar a linha rotulada rep.query(), verá que uma consulta JPQL é suficiente para carregar todos os dados. findAll()produz muitas consultas dispensáveis ​​e, portanto, é lento. findAll(Sort)adicionalmente retorna um número anormal de atores. Basicamente, independentemente da implementação de JPA subjacente, ambos os métodos de JpaRepositoryinterface não são muito úteis para dados relacionais.

Mostro a ordenação dos dados carregados e discuto os resultados numéricos com mais detalhes abaixo. Mas antes disso, tenho que explicar como os coletei para que pareçam confiáveis.

Medindo o tempo de execução do método e contando as seleções executadas pelo Hibernate ou EclipseLink

Em aplicativos da web, os dados geralmente são carregados para serem exibidos. Para serem exibidos, os dados devem estar completamente carregados. O JPA carrega associações muitos-para-muitos lentamente, ou seja, gradualmente quando são acessadas. Para comparar os tempos necessários para carregar os dados completos, meu código de benchmarking acessa todas as categorias aninhadas em todos os atores carregados.

Existem várias maneiras complicadas de contar o número de selects principalmente desnecessários. Usei o mais simples. Ativei o log do Hibernate ou EclipseLink adicionando spring.jpa.properties.hibernate.show_sql=trueou spring.jpa.properties.eclipselink.logging.level=FINE, respectivamente, a application.properties . Então eu simplesmente conto na saída padrão as linhas que começam com Hibernate: selectou [EL Fine]: sql: SELECT.

O código mede o tempo de execução de cada abordagem 15 vezes. Mas apenas as últimas 10 medições são usadas para contar o tempo médio. O código é simples, mas muito longo para parecer legível aqui. Você pode vê-lo no GitHub .

Carregando dados relacionais com JDBC puro

Comparado ao código dependente de camadas adicionais, como JPA, o código JDBC puro tem uma vantagem — uma vez desenvolvido, seus testes não falharão quando qualquer uma das dependências for atualizada.

Com JDBC todos os dados podem ser carregados com uma consulta SQL:

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

Observe que quero que os dados sejam classificados por nome do ator, título do filme e, finalmente, nome da categoria. Se JDBC ou EclipseLink for usado, isso pode ser obtido com a order bycláusula.

Há muitas maneiras de decompor um produto de junção em entidades associadas. Isso pode ser feito convenientemente com fluxos Java. O código se torna ainda mais direto com um coletor genérico personalizado. Você pode ver o código no GitHub . Eu não mostro aqui porque o código ainda é relativamente longo e, como você pode ver nos resultados do benchmarking, não é muito mais rápido que o código análogo baseado em JPA. Os fluxos são convenientes, mas estão associados a muitos códigos auxiliares genéricos e, portanto, são lentos.

As primeiras linhas dos dados carregados e classificados corretamente:

Não importa para este post, mas observe que, embora o esquema inclua uma relação muitos-para-muitos entre filmes e categorias, nenhum dos filmes no banco de dados Sakila está associado a mais de uma categoria.

Por causa do número irracional de seleções, findAll() é lento

Normalmente findAll()de JpaRepositorydeve ser usado apenas com entidades sem relacionamentos. Se as entidades carregadas tiverem associações, findAll()isso poderá fazer com que o aplicativo seja interrompido. Em meu experimento com dados irrealisticamente minúsculos, o findAll()método precisa de apenas ~4 vezes mais tempo do que a abordagem JDBC ou JPA. A maior parte do seu tempo de execução é gasto na execução de 1198 selects (1 selectpara carregar atores, 200 selects para carregar filmes e 997 selects para carregar categorias). Se o banco de dados contivesse uma quantidade de dados mais realista ou se o banco de dados não estivesse no host local, o tempo de execução seria muito maior. As consultas graduais dispensáveis ​​não são um problema do Spring Data, é um recurso bizarro do JPA — uma consulta é executada por cada entidade pai.

findAll(Sort) não classifica e retorna muito

Eu acho que raramente é aceitável carregar dados não classificados como os dados retornados pelo ineficiente findAll(). Mesmo que os dados devam ser reordenados no navegador em resposta à entrada do usuário, para a primeira renderização é bom ter os dados classificados. Os repositórios Spring Data oferecem um método findAll(Sort)que deve recuperar dados classificados. Em termos de tempo de execução, é tão ineficiente quanto findAll(). Estranhamente, retorna um Listcom 5462 atores em vez dos 200 esperados.

No meu código, o método é invocado com:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

Ele classifica com sucesso os autores por sobrenome e nome, mas não pode classificar os filmes por título.

Este é um problema causado pelo Hibernate, pois com EclipseLink a ordem está correta:

Modern Hibernate processa incorretamente junções de busca

Antes de discutir os resultados obtidos com consultas JPQL, preciso demonstrar uma diferença importante entre o moderno Hibernate 6 e o ​​obsoleto Hibernate 5 usado pelo Spring Data. O Hibernate 6 é incompatível com Spring Data e pouco compatível com Spring.

O JPA às vezes pode certamente simplificar o código. Todos os autores podem ser carregados com uma consulta JPQL menor que a consulta SQL equivalente acima. O código para carregar todos os atores é muito mais curto do que o código baseado em JDBC.

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

O Hibernate não oferece outra maneira de carregar entidades relacionadas com eficiência, exceto por fetch joins . Infelizmente, o mesmo código produz resultados diferentes com Hibernate 6 e Hibernate 5.

Você vê na tabela de resultados acima que o Hibernate obsoleto usado pelo Spring Data usa um selectpara carregar todos os dados, é tão rápido quanto o código JDBC, mas retorna um Listcom 5462 atores em vez de 200. Essa é uma característica do JPA -de acordo para a especificação JPA, as junções de busca devem produzir tantos resultados quanto as junções.

Em contraste, o Hibernate 6 retorna o número correto de atores. É conveniente e correto de acordo com o senso comum, mas de acordo com a especificação JPA é incorreto.

Nenhuma das versões do Hibernate preserva a ordem definida pela order bycláusula.

Por que usar interfaces de repositório para executar consultas JPQL

É possível usar interfaces de repositório para executar consultas JPQL. Nos repositórios, as consultas podem ser especificadas com @Queryanotação.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

O código não parece ser mais curto que o código baseado em JPA equivalente acima. Ela produz a mesma aberração Listcom 5.462 atores que a abordagem JPA acima.

Junções de busca aninhadas não são suportadas pelo EclipseLink, mas dicas de consulta podem ser usadas em vez disso. Com EclipseLink os resultados são muito melhores — 200 atores devidamente classificados. Vamos ver se há muita diferença entre o código JPA:

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

e o código JPA equivalente do Spring Data:

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

Claro que ao contrário do Hibernate, o EclipseLink retorna dados bem ordenados:

Portanto, não parece que o Spring Data JPA simplifique o código com consultas JPQL. Não faz sentido usar Spring Data JPA com consultas JPQL.

Como usar fetch joins com Spring Data JPA

Até que o Spring Data JPA comece a suportar um Hibernate mais moderno, os resultados aberrantes de fetch joins podem ser melhorados adicionando uma palavra-chave distinctà consulta JPQL.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

Agora a consulta produz os números esperados de entidades. Mas, como esperado para o Hibernate, eles não são classificados corretamente.

Métodos de consulta bonitos, mas ineficientes

A última linha na minha tabela de resultados numéricos serve apenas para observar que os métodos de consulta têm um preço - eles produzem muitos selects graduais desnecessários que levam tempo.

Conclusões

Se você souber como usá-lo, o JPA pode simplificar o código e não é muito mais lento que o JDBC puro. Spring ajuda a lidar com transações. O Spring Data JPA é uma camada adicional na parte superior do JPA e do Spring. Não está muito claro o que isso traz, exceto uma maneira elegante de definir consultas ineficientes com nomes de métodos em interfaces.

As interfaces de repositório podem ter dois tipos de métodos — métodos cujos nomes definem consultas JPQL (por exemplo findByFirstName(), ) e métodos que retornam resultados de consultas JPQL especificadas com @Queryanotação.

Não é aparente quando um banco de dados H2 na memória com poucos dados é usado, mas métodos sofisticados de interfaces de repositório têm um preço - eles são extremamente lentos. Se você usar bancos de dados relacionais para armazenar dados relacionais, os métodos ineficientes de consulta no nome não poderão substituir as consultas JPQL.

Mas não faz sentido usar uma dependência adicional do Spring Data JPA para executar consultas JPQL. O código equivalente sem o Spring Data JPA não é mais longo e pode usar EntityManagermétodos às vezes indispensáveis, como detach()ou persist()que não possuem interfaces de repositório.

Alguns dos problemas do Spring Data JPA são causados ​​por limitações do Hibernate. Quando usado com dados relacionais, o Hibernate não preserva a ordem definida pela order bycláusula nas consultas JPQL. Portanto, o método ineficiente findAll(Sort)não classifica a menos que o Hibernate seja substituído pelo EclipseLink. É estranho que o Spring Data JPA dependa da implementação do JPA que não parece ser totalmente compatível com os métodos contribuídos pelo Spring Data JPA.

No geral, o Spring Data JPA é mais adequado para aplicativos de demonstração com bancos de dados vazios. 

Fonte: https://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48

#hibernate #spring

O Suporte Do Spring Data JPA Para Carregar Dados Relacionais
曾 俊

曾 俊

1661171400

Spring Data JPA 对加载关系数据的支持

Spring Data 是用于存储数据的常用技术之上的附加层。Spring Data JPA 是 Spring Data 中最常用的部分,旨在通过消除重复的代码片段来简化基于 JPA 的代码。本质上 Spring Data JPA 是一种隐藏的 JPA EntityManager

在这篇文章中,我想探索 Spring Data JPA 对加载关系数据的支持。默认情况下,Spring Data JPA 依赖于 Hibernate。由于某些 Spring Data JPA 限制是由 Hibernate 引起的,因此我还使用更强大的 JPA 实现 EclipseLink 来评估 Spring Data JPA。

我比较了几种从 MySQL 数据库的 Sakila 示例模式中加载数据的方法。比较方法:

  • 我计算了执行的 SQL 查询的数量。默认情况下,JPA 实现对每个父实体执行一个查询。
  • 我测量加载数据所需的时间。时间取决于不必要select的 s 的数量。
  • 我检查加载的数据是否正确转换为实体。
  • 我检查数据是否正确排序。众所周知,Hibernate 会弄乱加载的关系数据中的顺序,但有趣的是知道它是否findAll(Sort)与关系数据兼容。

在我的实验中,我使用了三个 classes ActorFilmCategory映射到 Sakila 示例模式的五个表:

关系图是指一个演员可以演多部电影,每部电影可以包含很多演员。相同的类别被重新用于对电影进行分类。每部电影可以属于许多类别。数据包括200名演员、1000部电影和16个类别。我用三个实体加载数据:

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

这些表包含的列比我加载的多。为简化代码,我只加载最有意义的列。

还要注意 Hibernate 的一个毫无意义的限制。使用 one select,嵌套关联只能加载到Sets 中。EclipseLink 中不存在这种异常。因此,使用 EclipseLink,我将相关实体存储在Lists 中。与Sets 不同,Lists 保留了加载数据的顺序,并允许使用方法简单地访问它们的元素get()

几种不同的方法来为所有演员加载相关的电影和类别

首先,作为开始和参考结果,我将使用纯 JDBC 代码。然后我评估的findAll()findAll(Sort)方法JpaRepository。为了表明存储库产生的一些异常是因为 Spring Data JPA 依赖于过时的 Hibernate 版本,我将 Spring Data 使用的 Hibernate 5.6.9 与现代 Hibernate 6 进行了比较。然后我评估了两种使用@Query注释修饰的方法。最后,我展示了美观的存储库方法,例如findByFirstName()生成大量可有可无的查询。

以下是数字结果:

休眠

EclipseLink

Hibernate 和 EclipseLink 之间有一些相似之处。如果查看标记为 的行rep.query(),您会看到一个 JPQL 查询足以加载所有数据。findAll()产生大量可有可无的查询,因此速度很慢。findAll(Sort)另外返回异常数量的演员。基本上,不管底层的 JPA 实现如何,这两种JpaRepository接口方法对关系数据都不是很有用。

我展示了加载数据的顺序,并在下面更详细地讨论了数值结果。但在此之前,我必须解释我是如何收集它们的,以便它们看起来可信。

测量由 Hibernate 或 EclipseLink 执行的方法执行时间和计数选择

在 Web 应用程序中,通常会加载数据以进行显示。要显示数据,必须完全加载。JPA 延迟加载多对多关联,即在访问它们时逐渐加载。为了比较加载完整数据所需的时间,我的基准测试代码访问了所有加载的参与者中的所有嵌套类别。

有几种棘手的方法可以计算大部分不需要select的 s 的数量。我用的是最直接的。我通过分别添加spring.jpa.properties.hibernate.show_sql=true或添加到application.properties来打开 Hibernate 或 EclipseLink 日志记录。然后我只需在标准输出中计算以or开头的行。spring.jpa.properties.eclipselink.logging.level=FINEHibernate: select[EL Fine]: sql: SELECT

该代码测量了每种方法的执行时间 15 次。但只有最后 10 次测量用于计算平均时间。代码很简单,但是太长了,在这里看不太清楚。你可以在GitHub中看到它。

使用纯 JDBC 加载关系数据

与依赖于 JPA 等附加层的代码相比,纯 JDBC 代码有一个优势——一旦开发出来,当任何依赖项升级时,它的测试都不会失败。

使用 JDBC,所有数据都可以通过一个 SQL 查询加载:

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

请注意,我希望数据按演员姓名、电影名称和类别名称排序。如果使用 JDBC 或 EclipseLink,这可以通过order by子句来实现。

有许多方法可以将连接产品分解为关联实体。使用 Java 流可以很方便地完成它。使用自定义通用收集器,代码变得更加简单。您可以在GitHub中查看代码。我没有在这里展示它,因为代码仍然相对较长,并且正如您在基准测试结果中看到的那样,它并不比类似的基于 JPA 的代码快多少。流很方便,但与许多通用辅助代码相关联,因此速度很慢。

加载并正确排序的数据的第一行:

这篇文章无关紧要,但请注意,虽然模式包括电影和类别之间的多对多关系,但 Sakila 数据库中的电影都没有与一个以上的类别相关联。

由于不合理的选择次数 findAll() 很慢

通常findAll()ofJpaRepository应该只用于没有关系的实体。如果加载的实体有关联,findAll()可能会成功导致应用程序挂起。在我对不切实际的小数据进行的实验中,findAll()方法只需要比 JDBC 或 JPA 方法多约 4 倍的时间。它的大部分执行时间都花在了 1198select秒的执行上(1 秒select加载演员,200select秒加载电影,997select秒加载类别)。如果数据库包含更真实的数据量,或者数据库不在本地主机上,则执行时间会长得多。可有可无的渐进查询不是 Spring Data 的问题,它是 JPA 的一个奇怪特性——每个父实体执行一个查询。

findAll(Sort) 不排序,返回太多

我想加载未排序的数据(如低效返回的数据)很少是可以接受的findAll()。即使要在浏览器中使用数据以响应用户输入,对于第一次渲染来说,对数据进行排序也很不错。Spring Data 存储库提供了一种findAll(Sort)应该检索已排序数据的方法。就执行时间而言,它与findAll(). 奇怪的是,它返回了List5462 个演员,而不是预期的 200 个。

我的代码调用了该方法:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

它成功地按作者的姓氏和名字对作者进行排序,但不能按标题对电影进行排序。

这个问题是由 Hibernate 引起的,因为使用 EclipseLink 的顺序是正确的:

现代 Hibernate 错误地处理 fetch 连接

在讨论使用 JPQL 查询获得的结果之前,我需要演示现代 Hibernate 6 和 Spring Data 使用的过时 Hibernate 5 之间的重要区别。Hibernate 6 与 Spring Data 不兼容,与 Spring 几乎不兼容。

JPA 有时当然可以简化代码。所有作者都可以加载一个比上述等效 SQL 查询短的 JPQL 查询。加载所有参与者的代码比基于 JDBC 的代码要短得多。

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

除了fetch joins之外,Hibernate 没有提供其他有效加载相关实体的方法。不幸的是,相同的代码在 Hibernate 6 和 Hibernate 5 中产生不同的结果。

您在上面的结果表中看到 Spring Data 使用的过时 Hibernate 使用一个select来加载所有数据,它与 JDBC 代码一样快,但它返回一个List5462 个actors 而不是 200 个。这是 JPA 的一个特性 -according根据 JPA 规范,获取连接必须产生与连接一样多的结果。

相反,Hibernate 6 返回正确数量的参与者。根据常识,它既方便又正确,但根据 JPA 规范,它是不正确的。

两个版本的 Hibernate 都没有保留由order by子句设置的顺序。

为什么使用存储库接口来执行 JPQL 查询

可以使用存储库接口来执行 JPQL 查询。在存储库中,可以使用@Query注释指定查询。

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

该代码似乎并不比上面等效的基于 JPA 的代码短。List它产生与上述 JPA 方法相同的 5462 个参与者异常。

EclipseLink 不支持嵌套获取连接,但可以使用查询提示。使用 EclipseLink,结果要好得多—— 200 个正确排序的演员。让我们看看JPA代码之间是否有很大区别:

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

和等效的 Spring Data JPA 代码:

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

当然,与 Hibernate 不同的是,EclipseLink 返回有序的数据:

因此,Spring Data JPA 似乎并没有使用 JPQL 查询来简化代码。将 Spring Data JPA 与 JPQL 查询一起使用是没有意义的。

如何在 Spring Data JPA 中使用 fetch 连接

在 Spring Data JPA 开始支持更现代的 Hibernate 之前,可以通过向JPQL 查询添加关键字来改善fetch join的异常结果。distinct

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

现在查询产生了预期数量的实体。但正如 Hibernate 所期望的那样,它们没有正确排序。

好看但效率低的查询方法

我的数字结果表中的最后一行只是用来说明查询方法是有代价的——它们会产生大量不需要的渐进式selects 并且需要时间。

结论

如果您知道如何使用它,JPA 可以简化代码,并且它不会比纯 JDBC 慢多少。Spring 有助于处理事务。Spring Data JPA 是在 JPA 和 Spring 之上的附加层。除了在接口中使用方法名称定义低效查询的一种奇特方式之外,它带来了什么并不是很清楚。

存储库接口可以有两种类型的方法——名称定义 JPQL 查询的方法(例如findByFirstName())和返回使用@Query注释指定的 JPQL 查询结果的方法。

何时使用数据很少的内存 H2 数据库并不明显,但存储库接口的奇特方法是有代价的——它们最慢。如果您使用关系数据库来存储关系数据,那么低效的名称查询方法无法替代 JPQL 查询。

但是使用额外的 Spring Data JPA 依赖项来执行 JPQL 查询是没有意义的。没有 Spring Data JPA 的等效代码不再存在,并且有时可以使用诸如缺少存储库接口之类的不可或缺的EntityManager方法。detach()persist()

Spring Data JPA 的一些问题是由于 Hibernate 的限制造成的。当与关系数据一起使用时,Hibernate 不保留order byJPQL 查询中的 order set by 子句。因此,findAll(Sort)除非用 EclipseLink 替换 Hibernate,否则效率低下的方法不会排序。奇怪的是,Spring Data JPA 依赖的 JPA 实现似乎与 Spring Data JPA 贡献的方法并不完全兼容。

总体而言,Spring Data JPA 最适合具有空数据库的演示应用程序。 

来源:https ://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48

#hibernate #spring

Spring Data JPA 对加载关系数据的支持

El Soporte De Spring Data JPA Para Cargar Datos Relacionales

Spring Data es una capa adicional por encima de las tecnologías comunes para almacenar datos. Se supone que Spring Data JPA, la parte más utilizada de Spring Data, simplifica el código basado en JPA al eliminar piezas de código recurrentes. Esencialmente Spring Data JPA es un tipo de JPA con EntityManager.

En esta publicación, quiero explorar el soporte de Spring Data JPA para cargar datos relacionales. Spring Data JPA, por defecto, depende de Hibernate. Dado que algunas de las limitaciones de Spring Data JPA son causadas por Hibernate, también evalúo Spring Data JPA con una implementación de JPA más potente, EclipseLink.

Comparo varias formas de cargar datos del pequeño esquema de muestra Sakila de la base de datos MySQL. Para comparar enfoques:

  • Cuento el número de consultas SQL ejecutadas. De forma predeterminada, las implementaciones de JPA ejecutan una consulta por cada entidad principal.
  • Mido el tiempo necesario para cargar los datos. El tiempo depende del número de selects innecesarios.
  • Compruebo si los datos cargados se convierten correctamente en entidades.
  • Verifico que los datos estén ordenados correctamente. Se sabe que Hibernate altera el orden de los datos relacionales cargados, pero es interesante saber si findAll(Sort)es compatible con los datos relacionales.

ActorEn mis experimentos , utilizo tres clases Filmy Categorylas asigné a cinco tablas del esquema de muestra de Sakila:

El diagrama de relaciones significa que un actor puede actuar en muchas películas, y cada película puede incluir muchos actores. Las mismas categorías se reutilizan para clasificar las películas. Cada película puede pertenecer a muchas categorías. Los datos incluyen 200 actores, 1000 películas y 16 categorías. Cargo los datos con tres entidades:

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

Las tablas contienen más columnas de las que cargo. Para simplificar el código, cargo solo las columnas más significativas.

También tenga en cuenta una limitación sin sentido de Hibernate. Con one select, las asociaciones anidadas solo se pueden cargar en Sets. Esta aberración no existe en EclipseLink. Entonces, con EclipseLink almaceno entidades relacionadas en Lists. A diferencia Setde s, Lists conserva el orden de los datos cargados y permite un acceso simple a sus elementos con el método get().

Varios enfoques diferentes para cargar a todos los actores con películas y categorías asociadas.

Primero, como resultado inicial y de referencia, usaré un código puro basado en JDBC. Luego evalúo los métodos findAll()y de . Para mostrar que algunas de las aberraciones producidas por los repositorios ocurren porque Spring Data JPA depende de una versión obsoleta de Hibernate, comparo el Hibernate 5.6.9 usado por Spring Data con el moderno Hibernate 6. Luego evalúo dos métodos decorados con anotaciones. Finalmente, muestro que los métodos de repositorio atractivos generan muchas consultas prescindibles.findAll(Sort)JpaRepository@QueryfindByFirstName()

Estos son los resultados numéricos:

Hibernar

EclipseLink

Hay algunas similitudes entre Hibernate y EclipseLink. Si observa la fila etiquetada rep.query(), verá que una consulta JPQL es suficiente para cargar todos los datos. findAll()produce muchas consultas prescindibles y, por lo tanto, es lento. findAll(Sort)además devuelve un número anormal de actores. Básicamente, independientemente de la implementación de JPA subyacente, ambos métodos de JpaRepositoryinterfaz no son muy útiles para datos relacionales.

Muestro el orden de los datos cargados y analizo los resultados numéricos con más detalle a continuación. Pero antes de eso, tengo que explicar cómo los recopilé para que se vean creíbles.

Medición del tiempo de ejecución del método y conteo de selecciones ejecutadas por Hibernate o EclipseLink

En las aplicaciones web, los datos generalmente se cargan para mostrarse. Para que se muestren, los datos deben estar completamente cargados. JPA carga asociaciones de muchos a muchos de forma perezosa, es decir, gradualmente cuando se accede a ellas. Para comparar los tiempos necesarios para cargar los datos completos, mi código de evaluación comparativa accede a todas las categorías anidadas en todos los actores cargados.

Hay varias formas complicadas de contar el número de selects en su mayoría innecesarios. Usé el más directo. Encendí el registro de Hibernate o EclipseLink agregando spring.jpa.properties.hibernate.show_sql=trueo spring.jpa.properties.eclipselink.logging.level=FINE, respectivamente, a application.properties . Luego simplemente cuento en la salida estándar las líneas que comienzan con Hibernate: selecto [EL Fine]: sql: SELECT.

El código mide el tiempo de ejecución de cada enfoque 15 veces. Pero solo las últimas 10 mediciones se utilizan para contar el tiempo promedio. El código es simple pero demasiado largo para parecer legible aquí. Puedes verlo en el GitHub .

Cargando datos relacionales con JDBC puro

En comparación con el código que depende de capas adicionales como JPA, el código JDBC puro tiene una ventaja: una vez que se desarrolla, sus pruebas no fallarán cuando se actualice cualquiera de las dependencias.

Con JDBC, todos los datos se pueden cargar con una consulta SQL:

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

Tenga en cuenta que quiero que los datos se ordenen por nombre de actor, título de película y, finalmente, nombre de categoría. Si se usa JDBC o EclipseLink, esto se puede lograr con order byla cláusula.

Hay muchas formas de descomponer un producto de unión en entidades asociadas. Se puede hacer muy convenientemente con flujos de Java. El código se vuelve aún más sencillo con un recopilador genérico personalizado. Puedes ver el código en GitHub . No lo muestro aquí porque el código aún es relativamente largo y, como puede ver en los resultados de la evaluación comparativa, no es mucho más rápido que el código análogo basado en JPA. Los flujos son convenientes pero están asociados con una gran cantidad de código auxiliar genérico y, por lo tanto, son lentos.

Las primeras filas de los datos cargados y correctamente ordenados:

No importa para esta publicación, pero tenga en cuenta que, aunque el esquema incluye una relación de muchos a muchos entre películas y categorías, ninguna de las películas en la base de datos de Sakila está asociada con más de una categoría.

Debido a un número irrazonable de selecciones, findAll() es lento

Normalmente findAll()of JpaRepositorydebe usarse solo con entidades sin relaciones. Si las entidades cargadas tienen asociaciones, findAll()es posible que la aplicación se cuelgue correctamente. En mi experimento con datos minúsculos poco realistas, el findAll()método necesita solo ~4 veces más tiempo que el enfoque JDBC o JPA. La mayor parte de su tiempo de ejecución se dedica a la ejecución de 1198 selects (1 selectpara cargar actores, 200 selects para cargar películas y 997 selects para cargar categorías). Si la base de datos contuviera una cantidad de datos más realista o si la base de datos no estuviera en el host local, el tiempo de ejecución sería mucho mayor. Las consultas graduales prescindibles no son un problema de Spring Data, es una característica extraña de JPA: se ejecuta una consulta por cada entidad principal.

findAll(Sort) no ordena y devuelve demasiado

Supongo que rara vez es aceptable cargar datos no ordenados como los datos devueltos por el ineficiente findAll(). Incluso si los datos se van a consultar en el navegador en respuesta a la entrada del usuario, para el primer procesamiento es bueno tener datos ordenados. Los repositorios de Spring Data ofrecen un método findAll(Sort)que se supone que recupera datos ordenados. En cuanto al tiempo de ejecución, es tan ineficiente como findAll(). Extrañamente, devuelve un Listcon 5462 actores en lugar de los 200 esperados.

En mi código, el método se invoca con:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

Ordena con éxito a los autores por su apellido y nombre, pero no puede ordenar las películas por su título.

Este problema es causado por Hibernate, porque con EclipseLink el orden es correcto:

Hibernate moderno procesa incorrectamente las uniones de búsqueda

Antes de discutir los resultados obtenidos con las consultas JPQL, necesito demostrar una diferencia importante entre el moderno Hibernate 6 y el obsoleto Hibernate 5 utilizado por Spring Data. Hibernate 6 es incompatible con Spring Data y apenas compatible con Spring.

JPA a veces ciertamente puede simplificar el código. Todos los autores se pueden cargar con una consulta JPQL que es más corta que la consulta SQL equivalente anterior. El código para cargar todos los actores es mucho más corto que el código basado en JDBC.

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

Hibernate no ofrece otra forma de cargar entidades relacionadas de manera eficiente, excepto mediante búsqueda de uniones . Desafortunadamente, el mismo código produce resultados diferentes con Hibernate 6 e Hibernate 5.

Puede ver en la tabla de resultados anterior que el obsoleto Hibernate utilizado por Spring Data usa uno selectpara cargar todos los datos, es tan rápido como el código JDBC, pero devuelve un Listcon 5462 actores en lugar de 200. Esa es una característica de JPA, según según la especificación JPA, las uniones de búsqueda tienen que producir tantos resultados como uniones.

Por el contrario, Hibernate 6 devuelve el número correcto de actores. Es conveniente y correcto según el sentido común, pero según la especificación JPA es incorrecto.

Ninguna versión de Hibernate conserva el orden establecido por la order bycláusula.

¿Por qué usar interfaces de repositorio para ejecutar consultas JPQL?

Es posible utilizar interfaces de repositorio para ejecutar consultas JPQL. En los repositorios, las consultas se pueden especificar con @Queryanotación.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

El código no parece ser más corto que el código equivalente basado en JPA anterior. Produce la misma aberración Listcon 5462 actores que el enfoque JPA anterior.

EclipseLink no admite las uniones de búsqueda anidadas , pero en su lugar se pueden usar sugerencias de consulta . Con EclipseLink, los resultados son mucho mejores: 200 actores ordenados correctamente. A ver si hay mucha diferencia entre el código JPA:

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

y el código Spring Data JPA equivalente:

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

Por supuesto, a diferencia de Hibernate, EclipseLink devuelve datos bien ordenados:

Entonces no parece que Spring Data JPA simplifique el código con consultas JPQL. No tiene sentido usar Spring Data JPA con consultas JPQL.

Cómo usar combinaciones de búsqueda con Spring Data JPA

Hasta que Spring Data JPA comience a admitir un Hibernate más moderno, los resultados aberrantes de las uniones de búsqueda se pueden mejorar agregando una palabra clave distincta la consulta JPQL.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

Ahora la consulta produce el número esperado de entidades. Pero como era de esperar para Hibernate, no están ordenados correctamente.

Métodos de consulta atractivos pero ineficientes

La última línea en mi tabla de resultados numéricos solo sirve para señalar que los métodos de consulta tienen un precio: producen muchos s graduales innecesarios selectque toman tiempo.

Conclusiones

Si sabe cómo usarlo, JPA puede simplificar el código y no es mucho más lento que JDBC puro. Spring ayuda a lidiar con las transacciones. Spring Data JPA es una capa adicional sobre JPA y Spring. No está muy claro lo que trae, excepto una forma elegante de definir consultas ineficientes con nombres de métodos en las interfaces.

Las interfaces de repositorio pueden tener dos tipos de métodos: métodos cuyos nombres definen consultas JPQL (por ejemplo, findByFirstName()) y métodos que devuelven resultados de consultas JPQL especificadas con @Queryanotación.

No es evidente cuando se utiliza una base de datos H2 en memoria con pocos datos, pero los métodos sofisticados de las interfaces de repositorio tienen un precio: son extremadamente lentos. Si utiliza bases de datos relacionales para almacenar datos relacionales, los métodos de consulta en nombre ineficientes no pueden sustituir las consultas JPQL.

Pero no tiene sentido usar una dependencia adicional de Spring Data JPA para ejecutar consultas JPQL. El código equivalente sin Spring Data JPA no es más largo y puede usar EntityManagermétodos a veces indispensables como detach()o persist()que faltan interfaces de repositorio.

Algunos de los problemas de Spring Data JPA son causados ​​por limitaciones de Hibernate. Cuando se usa con datos relacionales, Hibernate no conserva el orden establecido por la order bycláusula en las consultas JPQL. Por lo tanto, el método ineficiente findAll(Sort)no ordena a menos que Hibernate se reemplace con EclipseLink. Es extraño que Spring Data JPA dependa de la implementación de JPA que no parece ser totalmente compatible con los métodos aportados por Spring Data JPA.

En general, Spring Data JPA es más adecuado para aplicaciones de demostración con bases de datos vacías. 

Fuente: https://itnext.io/advantages-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48 

#hibernate #spring

El Soporte De Spring Data JPA Para Cargar Datos Relacionales
Duong Tran

Duong Tran

1661167800

Sự Hỗ Trợ Của Spring Data JPA để Tải Dữ Liệu Quan Hệ

Dữ liệu mùa xuân là một lớp bổ sung bên trên các công nghệ phổ biến để lưu trữ dữ liệu. Dữ liệu mùa xuân JPA, phần được sử dụng phổ biến nhất của Dữ liệu mùa xuân, được cho là đơn giản hóa mã dựa trên JPA bằng cách loại bỏ các đoạn mã lặp lại. Về cơ bản Spring Data JPA là một loại JPA ẩn EntityManager.

Trong bài đăng này, tôi muốn khám phá sự hỗ trợ của Spring Data JPA để tải dữ liệu quan hệ. Spring Data JPA, theo mặc định, phụ thuộc vào Hibernate. Vì một số hạn chế của Spring Data JPA là do Hibernate gây ra, tôi cũng đánh giá thêm Spring Data JPA bằng EclipseLink triển khai JPA mạnh mẽ hơn.

Tôi so sánh một số cách tải dữ liệu từ lược đồ mẫu Sakila nhỏ của cơ sở dữ liệu MySQL. Để so sánh các cách tiếp cận:

  • Tôi đếm số lượng truy vấn SQL được thực thi. Theo mặc định, các triển khai JPA thực hiện một truy vấn cho mỗi thực thể mẹ.
  • Tôi đo thời gian cần thiết để tải dữ liệu. Thời gian phụ thuộc vào số lượng selects không cần thiết.
  • Tôi kiểm tra xem dữ liệu đã tải có được chuyển đổi chính xác thành các thực thể hay không.
  • Tôi kiểm tra dữ liệu được sắp xếp chính xác. Hibernate được biết là làm xáo trộn thứ tự trong dữ liệu quan hệ được tải, nhưng điều thú vị là biết liệu findAll(Sort)có tương thích với dữ liệu quan hệ hay không.

Trong các thử nghiệm của mình, tôi sử dụng ba lớp Actorvà ánh xạ Filmtới Categorynăm bảng của lược đồ mẫu Sakila:

Sơ đồ mối quan hệ có nghĩa là một diễn viên có thể đóng nhiều phim và mỗi phim có thể bao gồm nhiều diễn viên. Các danh mục tương tự được sử dụng lại để phân loại các bộ phim. Mỗi bộ phim có thể thuộc nhiều thể loại. Dữ liệu bao gồm 200 diễn viên, 1000 phim và 16 hạng mục. Tôi tải dữ liệu với ba thực thể:

@Entity
public class Actor {    @Id
    int actorId;    String firstName;
    String lastName;    @ManyToMany
    Set<Film> films;
}@Entity
public class Film {    @Id
    int filmId;
    String title;    @ManyToMany
    Set<Category> categories;
}@Entity
public class Category {    @Id
    int categoryId;
    String name;
}

Các bảng chứa nhiều cột hơn tôi tải. Để đơn giản hóa mã, tôi chỉ tải các cột có ý nghĩa nhất.

Cũng cần lưu ý một hạn chế vô nghĩa của Hibernate. Với một select, các liên kết lồng nhau chỉ có thể được tải vào Sets. Quang sai này không tồn tại trong EclipseLink. Vì vậy, với EclipseLink, tôi lưu trữ các thực thể liên quan trong Lists. Không giống như Sets, Lists bảo toàn thứ tự của dữ liệu được tải và cho phép truy cập đơn giản vào các phần tử của chúng bằng phương thức get().

Một số cách tiếp cận khác nhau để tải tất cả các diễn viên với các bộ phim và danh mục liên quan

Đầu tiên, là kết quả bắt đầu và tham chiếu, tôi sẽ sử dụng mã dựa trên JDBC thuần túy. Sau đó, tôi đánh giá các phương pháp findAll()và . Để chỉ ra rằng một số quang sai được tạo ra bởi các kho lưu trữ xảy ra do Spring Data JPA phụ thuộc vào phiên bản Hibernate lỗi thời, tôi so sánh Hibernate 5.6.9 được Spring Data sử dụng với Hibernate hiện đại 6. Sau đó, tôi đánh giá hai phương pháp được trang trí bằng chú thích. Cuối cùng, tôi chỉ ra rằng các phương pháp kho lưu trữ đẹp mắt chẳng hạn như tạo ra rất nhiều truy vấn không thể thiếu.findAll(Sort)JpaRepository@QueryfindByFirstName()

Đây là kết quả số:

Ngủ đông

EclipseLink

Có một số điểm tương đồng giữa Hibernate và EclipseLink. Nếu bạn nhìn vào hàng được gắn nhãn rep.query(), bạn thấy một truy vấn JPQL là đủ để tải tất cả dữ liệu. findAll()tạo ra nhiều truy vấn không thể thiếu và do đó chậm. findAll(Sort)bổ sung trả về số lượng tác nhân bất thường. Về cơ bản, bất kể việc triển khai JPA cơ bản như thế nào, cả hai phương pháp JpaRepositorygiao diện đều không hữu ích lắm cho dữ liệu quan hệ.

Tôi hiển thị thứ tự của dữ liệu đã tải và thảo luận chi tiết hơn về kết quả số bên dưới. Nhưng trước đó, tôi phải giải thích cách tôi thu thập chúng để chúng trông đáng tin cậy.

Thời gian thực hiện phương pháp đo và các lựa chọn đếm được thực thi bởi Hibernate hoặc EclipseLink

Trong các ứng dụng web, dữ liệu thường được tải để được hiển thị. Để được hiển thị, dữ liệu phải được tải hoàn toàn. JPA tải nhiều liên kết một cách lười biếng, đó là dần dần khi chúng được truy cập. Để so sánh thời gian cần thiết để tải dữ liệu hoàn chỉnh, mã điểm chuẩn của tôi truy cập vào tất cả các danh mục lồng nhau trong tất cả các tác nhân được tải.

Có một số cách phức tạp để đếm số lượng hầu hết không cần thiết select. Tôi đã sử dụng đơn giản nhất. Tôi đã bật ghi nhật ký Hibernate hoặc EclipseLink bằng cách thêm spring.jpa.properties.hibernate.show_sql=truehoặc spring.jpa.properties.eclipselink.logging.level=FINE, tương ứng, vào application.properties . Sau đó, tôi chỉ cần đếm trong đầu ra tiêu chuẩn các dòng bắt đầu bằng Hibernate: selecthoặc [EL Fine]: sql: SELECT.

Đoạn mã đo thời gian thực hiện của mỗi cách tiếp cận 15 lần. Nhưng chỉ 10 phép đo cuối cùng được sử dụng để đếm thời gian trung bình. Mã này đơn giản nhưng quá dài để có thể đọc được ở đây. Bạn có thể thấy nó trong GitHub .

Tải dữ liệu quan hệ với JDBC thuần túy

So với mã phụ thuộc vào các lớp bổ sung như JPA, mã JDBC thuần túy có lợi thế hơn - một khi nó được phát triển, các bài kiểm tra của nó sẽ không thất bại khi bất kỳ phụ thuộc nào được nâng cấp.

Với JDBC, tất cả dữ liệu có thể được tải bằng một truy vấn SQL:

select a.actor_id, a.first_name,a.last_name, f.film_id, f.title,
c.category_id, c.name from actor a
left join film_actor using(actor_id)
left join film f using(film_id)
left join film_category using(film_id)
left join category c using(category_id)
order by a.last_name,a.first_name, f.title, c.name

Lưu ý, tôi muốn dữ liệu được sắp xếp theo tên diễn viên, tên phim và cuối cùng là tên thể loại. Nếu JDBC hoặc EclipseLink được sử dụng, điều này có thể đạt được với order byđiều khoản.

Có nhiều cách để phân tách một sản phẩm kết hợp thành các thực thể liên kết. Nó có thể được thực hiện khá thuận tiện với các luồng Java. Mã trở nên đơn giản hơn với một bộ sưu tập chung tùy chỉnh. Bạn có thể xem mã trong GitHub . Tôi không hiển thị nó ở đây vì mã vẫn còn tương đối dài và, như bạn thấy trong kết quả đo điểm chuẩn, nó không nhanh hơn nhiều so với mã dựa trên JPA tương tự. Luồng rất thuận tiện nhưng được liên kết với rất nhiều mã phụ trợ chung và do đó chậm.

Các hàng đầu tiên của dữ liệu được tải và được sắp xếp đúng cách:

Điều đó không quan trọng đối với bài đăng này nhưng lưu ý, mặc dù lược đồ bao gồm mối quan hệ nhiều-nhiều giữa phim và danh mục, không phim nào trong cơ sở dữ liệu Sakila được liên kết với nhiều hơn một danh mục.

Do số lượng các lựa chọn không hợp lý, findAll () chậm

Thông thường findAll()của JpaRepositorychỉ nên được sử dụng với các thực thể không có mối quan hệ. Nếu các thực thể được tải có liên kết, findAll()thành công có thể khiến ứng dụng bị treo. Trong thử nghiệm của tôi với dữ liệu nhỏ không thực tế, findAll()phương pháp chỉ cần thời gian nhiều hơn ~ 4 lần so với phương pháp JDBC hoặc JPA. Hầu hết thời gian thực hiện của nó được dành cho việc thực hiện là 1198 selectgiây (1 selectđể tải diễn viên, 200 selectgiây để tải phim và 997 selectgiây để tải các thể loại). Nếu cơ sở dữ liệu chứa một lượng dữ liệu thực tế hơn hoặc nếu cơ sở dữ liệu không nằm trên localhost, thì thời gian thực thi sẽ lâu hơn nhiều. Các truy vấn dần dần không cần thiết không phải là vấn đề của Spring Data, nó là một tính năng kỳ lạ của JPA - một truy vấn được thực thi cho mỗi thực thể mẹ.

findAll (Sắp xếp) không sắp xếp và trả về quá nhiều

Tôi đoán rằng hiếm khi có thể chấp nhận được việc tải dữ liệu không được sắp xếp như dữ liệu được trả về bởi dữ liệu không hiệu quả findAll(). Ngay cả khi dữ liệu được sử dụng trong trình duyệt để đáp ứng với đầu vào của người dùng, đối với lần hiển thị đầu tiên, thật tuyệt khi dữ liệu được sắp xếp. Kho lưu trữ Dữ liệu mùa xuân cung cấp một phương pháp findAll(Sort)được cho là để lấy dữ liệu đã được sắp xếp. Về thời gian thực hiện, nó không hiệu quả bằng findAll(). Thật kỳ lạ, nó trả về một Listvới 5462 diễn viên thay vì 200 như mong đợi.

Tôi mã của tôi, phương thức được gọi với:

@GetMapping("/findAllSorted")
List<Actor> findAllSorted() {
    return rep.findAll(Sort.by("lastName", "firstName", "films.title", "films.categories.name"));
}

Nó sắp xếp thành công các tác giả theo họ và tên của họ nhưng không thể sắp xếp phim theo tiêu đề của họ.

Sự cố này là do Hibernate gây ra, vì với EclipseLink, thứ tự là đúng:

Modern Hibernate xử lý không chính xác các liên kết tìm nạp

Trước khi thảo luận về kết quả thu được với các truy vấn JPQL, tôi cần chứng minh sự khác biệt quan trọng giữa Hibernate 6 hiện đại và Hibernate 5 lỗi thời được sử dụng bởi Spring Data. Hibernate 6 không tương thích với Spring Data và hầu như không tương thích với Spring.

JPA đôi khi chắc chắn có thể đơn giản hóa mã. Tất cả các tác giả có thể được tải bằng một truy vấn JPQL ngắn hơn truy vấn SQL tương đương ở trên. Mã để tải tất cả các tác nhân ngắn hơn nhiều so với mã dựa trên JDBC.

@Repository
public class ActorJpaRepository {    @Autowired
    private EntityManager em;    public List<Actor> getAll() {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title,c.name", Actor.class).getResultList();
    }
}

Hibernate không cung cấp cách nào khác để tải các thực thể liên quan một cách hiệu quả ngoại trừ các phép nối tìm nạp . Thật không may, cùng một đoạn mã tạo ra các kết quả khác nhau với Hibernate 6 và Hibernate 5.

Bạn thấy trong bảng kết quả ở trên rằng Hibernate lỗi thời được sử dụng bởi Spring Data sử dụng một selectmã để tải tất cả dữ liệu, nó nhanh như mã JDBC, nhưng nó trả về a Listvới 5462 diễn viên thay vì 200. Đó là một tính năng của JPA-ghi hình đối với đặc tả JPA, các phép nối tìm nạp phải tạo ra nhiều kết quả như các phép nối.

Ngược lại Hibernate 6 trả về số lượng tác nhân chính xác. Nó thuận tiện và đúng theo cách hiểu thông thường, nhưng theo đặc điểm kỹ thuật của JPA thì nó không chính xác.

Không phiên bản nào của Hibernate duy trì thứ tự được đặt theo order bymệnh đề.

Tại sao sử dụng giao diện kho lưu trữ để thực hiện các truy vấn JPQL

Có thể sử dụng các giao diện kho lưu trữ để thực hiện các truy vấn JPQL. Trong kho lưu trữ, các truy vấn có thể được chỉ định bằng @Querychú thích.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> query();
}

Mã có vẻ không ngắn hơn mã dựa trên JPA tương đương ở trên. Nó tạo ra phương sai tương tự Listvới 5462 tác nhân như cách tiếp cận JPA ở trên.

Các phép nối tìm nạp lồng nhau không được EclipseLink hỗ trợ, nhưng thay vào đó bạn có thể sử dụng các gợi ý truy vấn . Với EclipseLink, kết quả tốt hơn nhiều - 200 tác nhân được sắp xếp đúng cách. Hãy xem có sự khác biệt nhiều giữa mã JPA không:

@Repository
public class ActorJpaRepository {    @Autowired
    EntityManager em;    public List<Actor> getAll () {
        return em.createQuery("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name", Actor.class).setHint("eclipselink.left-join-fetch", "a.films.categories").getResultList();
    }
}

và mã Spring Data JPA tương đương:

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT a FROM Actor a LEFT JOIN a.films f LEFT JOIN f.categories c order by a.lastName, a.firstName, f.title, c.name")
    @QueryHints({@QueryHint(name = "eclipselink.left-join-fetch", value = "a.films.categories")})
    List<Actor> query();
}

Tất nhiên không giống như Hibernate, EclipseLink trả về dữ liệu có thứ tự độc đáo:

Vì vậy, có vẻ như Spring Data JPA không đơn giản hóa mã với các truy vấn JPQL. Không có ích gì khi sử dụng Spring Data JPA với các truy vấn JPQL.

Cách sử dụng kết hợp tìm nạp với Spring Data JPA

Cho đến khi Spring Data JPA bắt đầu hỗ trợ Hibernate hiện đại hơn, kết quả sai lệch của các phép nối tìm nạp có thể được cải thiện bằng cách thêm một từ khóa distinctvào truy vấn JPQL.

@Repository
public interface ActorRepository extends JpaRepository<Actor, Integer> {    @Query("SELECT distinct a FROM Actor a LEFT JOIN FETCH a.films f LEFT JOIN FETCH f.categories c order by a.lastName, a.firstName, f.title, c.name")
    List<Actor> queryDistinct();
}

Bây giờ truy vấn tạo ra số lượng thực thể dự kiến. Nhưng như mong đợi đối với Hibernate, chúng không được sắp xếp đúng.

Phương thức truy vấn đẹp nhưng không hiệu quả

Dòng cuối cùng trong bảng kết quả số của tôi chỉ phục vụ để lưu ý rằng các phương thức truy vấn có giá - chúng tạo ra rất nhiều lần dần dần không cần thiết selectvà mất thời gian.

Kết luận

Nếu bạn biết cách sử dụng nó, JPA có thể đơn giản hóa mã và nó không chậm hơn nhiều so với JDBC thuần túy. Mùa xuân giúp giải quyết các giao dịch. Spring Data JPA là một lớp bổ sung trên đầu JPA và Spring. Không rõ nó mang lại những gì ngoại trừ một cách ưa thích để xác định các truy vấn không hiệu quả với tên phương thức trong giao diện.

Giao diện kho lưu trữ có thể có hai loại phương thức - phương thức có tên xác định các truy vấn JPQL (ví dụ findByFirstName()) và phương thức trả về kết quả của các truy vấn JPQL được chỉ định bằng @Querychú thích.

Không rõ khi nào thì cơ sở dữ liệu H2 trong bộ nhớ với ít dữ liệu được sử dụng, nhưng các phương pháp ưa thích của giao diện kho lưu trữ có giá - chúng chậm tối đa. Nếu bạn sử dụng cơ sở dữ liệu quan hệ để lưu trữ dữ liệu quan hệ, các phương thức tên truy vấn không hiệu quả không thể thay thế các truy vấn JPQL.

Nhưng không có ích gì khi sử dụng phụ thuộc Spring Data JPA bổ sung để thực hiện các truy vấn JPQL. Mã tương đương không có Spring Data JPA không dài hơn và đôi khi có thể sử dụng EntityManagercác phương pháp không thể thiếu, chẳng hạn như detach()hoặc persist()các giao diện kho lưu trữ bị thiếu.

Một số vấn đề của Spring Data JPA là do các hạn chế của Hibernate. Khi được sử dụng với dữ liệu quan hệ, Hibernate không bảo toàn thứ tự được đặt theo order bymệnh đề trong các truy vấn JPQL. Do đó, phương pháp không hiệu quả findAll(Sort)không sắp xếp trừ khi Hibernate được thay thế bằng EclipseLink. Thật kỳ lạ là Spring Data JPA phụ thuộc vào việc triển khai JPA dường như không hoàn toàn tương thích với các phương pháp do Spring Data JPA đóng góp.

Nhìn chung, Spring Data JPA phù hợp nhất cho các ứng dụng demo với cơ sở dữ liệu trống. 

Nguồn: https://itnext.io/ domains-of-not-using-spring-data-and-hibernate-with-relational-data-8a509faf0c48 

#hibernate #spring

Sự Hỗ Trợ Của Spring Data JPA để Tải Dữ Liệu Quan Hệ

Building blogAPI With CRUD REST API Using Spring & Mysql

blogAPI

A simple blog post api made with spring,mysql.Following tutorial by @FadatareRamesh(Java Guides)
Frontend server(made using Angular) can be found here Blog

Intro

A Blog API with functionalities listed below

  •  Build CRUD REST API for blog
  •  Add Pagination and Sorting
  •  Build REST API for login and signup
  •  Add Exception and error handling
  •  REST API Request Validation
  •  Add Spring Security and create role based authentication
  •  Use JWT based authentication
  •  Document REST API using swagger
  •  Use any of mapper(mapStruct,modelMapper,JMapper)
  •  Add Like functionality to Post

Technologies Used

  • Java 11
  • MySQL 8
  • Hibernate
  • Spring Security
  • Swagger

Download details:
Author: VasuSagar
Source code: https://github.com/VasuSagar/BlogAPI
License:

#spring #java #springboot #mysql #hibernate

Building blogAPI With CRUD REST API Using Spring & Mysql

Instructions for Spring Boot, Hibernate & Database

Spring-DAO-ORM-JEE-Web-AOP-Core-Boot

Spring Framework Architecure and Spring Framework Runtime details....

SpringBoot-DAO-ORM-Web

More valuable information also here (let's go)

Project-1. Spring Boot REST API JDBC MySQL Gradle

  • Gradle project provides Spring Boot and JDBC (using Gradle)

Project-2. Spring Boot REST API JDBC MySQL Maven

  • Family Member small project provides Spring Boot and JDBC template (using MySQL) implementation. In case of, Spring Boot using Maven configuration, and DB (database) using JDBC (only template not JPA ).

Project-3. SpringMVC-Boot2-JSP-JPA-Hibernate5-MySQL

Project-4. SpringBoot-ToDo-Project

  • Todo project provides Spring Boot and JDBC template (using MySQL) implementation. In case of, Spring Boot using Maven configuration, and DB (database) using JDBC (only template not JPA ).
  • The mainly 2 parameters: Adding todo list of the daily, List all of DB todo lists.

Project-5.SpringBoot-UploadFiles and Image

  • Spring Boot + Thyeamleaf + Web : Project which uploading files existing source code (upload) folder.

Project6 - Spring Boot Upload and Downloading File MySQLDB

  • Spring Boot + Web + MySQL Thyeamleaf.
  • Uplad and Download files Store in DB (MySQL in example)

Project7 - Spring Boot REST API - JPA- Hibernate-Thymeleaf

  • Spring Boot + Web + MySQL Thyeamleaf.
  • Project of Goverment population control related to People Inforamtion CRUD process. ->Project1- Spring Boot REST API- MySQL-Thymeleaf: Just adding and updating people to DB(MySQL), using Spring Boot, MySQL, Hibernate + Thymeleaf template 
    -> Project2- Spring Boot REST API- MySQL-Thymeleaf-Many-to-Many: Just adding and updating + SEARCHING bar people to DB(MySQL), using Spring Boot, MySQL, Hibernate + Thymeleaf template -> Project3- Spring Boot REST API- MySQL-Thymeleaf- Country Selection, Time selection, difference (Backed end thymeleaf): Just adding and updating people to DB(MySQL), using Spring Boot, MySQL, Hibernate + Thymeleaf template

Project8 -Simple-Build-CRUD-MySQL-JPA-Hibernate-okta-OAuth2

  • Spring Boot + Web + MySQL Thyeamleaf + Security.
  • Ongoing project Updating

Project9-RealProject-Populations

  • Spring Boot
  • Hibernate JPA
  • MySQL
  • Security
  • Sorting/Paginatation
  • Converting
  • Admin/User Controleres

Population_Final3

Core data for Spring Boot with Database details....

This provides Database implementation in the Spring Boot. Indeed, We should breifly inform here concept of Spring, Spring Boot, JDBC, JPA, H2.

Download Details:
Author: 
Source Code: 
License:

#spring #springboot #java #database #hibernate 

Instructions for Spring Boot, Hibernate & Database

How to Show Hibernate/JPA SQL Statements from Spring Boot

1. Overview

Spring JDBC and JPA provide abstractions over native JDBC APIs, allowing developers to do away with native SQL queries. However, we often need to see those auto-generated SQL queries and the order in which they were executed for debugging purposes.

In this quick tutorial, we're going to look at different ways of logging these SQL queries in Spring Boot.

2. Logging JPA Queries

2.1. To Standard Output

The simplest way to dump the queries to standard out is to add the following to application.properties:

spring.jpa.show-sql=true

To beautify or pretty print the SQL, we can add:

spring.jpa.properties.hibernate.format_sql=true

While this is extremely simple, it's not recommended, as it directly unloads everything to standard output without any optimizations of a logging framework.

Moreover, it doesn't log the parameters of prepared statements.

2.2. Via Loggers

Now let's see how we can log the SQL statements by configuring loggers in the properties file:

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

The first line logs the SQL queries, and the second statement logs the prepared statement parameters.

The pretty print property will work in this configuration as well.

By setting these properties, logs will be sent to the configured appender. By default, Spring Boot uses logback with a standard out appender.

3. Logging JdbcTemplate Queries

To configure statement logging when using JdbcTemplate, we need the following properties:

logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE

Similar to the JPA logging configuration, the first line is for logging statements and the second is to log parameters of prepared statements.

4. How Does It Work?

The Spring/Hibernate classes, which generate SQL statements and set the parameters, already contain the code for logging them.

However, the level of those log statements is set to DEBUG and TRACE respectively, which is lower than the default level in Spring Boot — INFO.

By adding these properties, we are just setting those loggers to the required level.

5. Conclusion

In this short article, we've looked at the ways to log SQL queries in Spring Boot.

If we choose to configure multiple appenders, we can also separate SQL statements and other log statements into different log files to keep things clean.

Link: https://www.baeldung.com/sql-logging-spring-boot

#spring  #springboot  #java #hibernate #sql 

How to Show Hibernate/JPA SQL Statements from Spring Boot

Hibernate Automatic Dirty Checking and The Persistence Context

In this lesson we will have a detailed walkthrough on the Hibernate Automatic dirty checking and the Persistence context. One of the frequently asked question in Hibernate framework Interview is the Update Vs Merge method and the way things work. We will cover this in a much detailed manner along with the Log4j integration with the Hibernate.

Timestamp : 
Introduction -  00:00:00
Log4J integration with Hibernate  - 00:03:18
Persistence Context & Hibernate Automatic Dirty Checking - 00:11:08
Hibernate Internals ( Snapshots ) - 00:20:42
Update Vs Merge method in JPA / Hibernate - 00:46:58
NonUniqueObjectException and the solution - 01:02:18

Prepare the above if you looking for hibernate interview questions for experienced category as well.

#hibernate  #crud #jpa  #java 

Hibernate Automatic Dirty Checking and The Persistence Context

4 Must Know Hibernate Operations #CRUD

So, We are all set to program our first  java hibernate CRUD application , Step by Step. We will explore different api methods present inside Hibernate / JPA api methods to fetch/load, Read, Delete and update data inside a java app.


After the first 50 mins of this lesson , We will try to think about a problem by doing some debugging. The problem will leads us to create a Singleton session factory by following the GOF singleton design pattern. So Sit back, Relax , a lot to do.. Here goes the time stamp.


introduction : 00:00:00
Recap : Hibernate Concepts explained: 00:02:32
Difference Between configure() vs Configure(..) : 00:07:18
Object mapping (ORM) in action : 00:13:15
Need of @Table: 00:15:19
Hibernate Create using save() :
Hibernate Read Operation :  00:21:06
Hibernate Read using get() : 00:24:29
Hibernate Read using load() : 00:27:07
Hibernate Update using update() : 00:32:42
Hibernate Delete using delete() : 00:45:10
Code Improvement - The Problem : 00:54:37
Design a singleton SessionFactory : 01:07:08
Testing code with debugging : 01:12:15
Fun fact : How the update is working here ? : 01:19:32
Handle Exception in Hibernate Framework Java : 01:23:00


#hibernate  #crud #jpa  #java 

4 Must Know Hibernate Operations #CRUD

Code A Hibernate App in 100 Minutes for Beginners / Experienced

This Lesson will get you started with the Java Hibernate - The ORM Framework. The goal of this lesson is to build your foundation and help you to write your first hibernate application from scratch. By the end of this lesson you will learn to write a hibernate config file by writing it from absolute scratch and, you will be having a clear cut understanding on different components on hibernate like Entity, Mappings , Configuration , Session, SessionFactory, Transaction and etc.

In this lesson we will code, we will get dirty with different hibernate exceptions and, we will also learn to fix those exceptions. This will help us to solve more real time problem and help us building a solid foundation on hibernate ORM.


Introduction : 00:00:00
What is ORM? : 00:00:49
What is JPA ? : 00:06:24
Hibernate Vs JPA : 00:14:44
What is Hibernate in java ? 00:19:29
Why Hibernate is popular ? 00:21:33
Creating a DB table :  00:22:26
Create a Maven project : 00:24:20
Tutorial goal : Save an java object state to mysql : 00:25:28
Adding Hibernate Dependency in maven: 00:27:55
Hibernate Configuration Object : 00:32;35
Creating a hibernate config file: 00:36:23
Hibernate Session Factory  Object: 00:40:46
Hibernate config Properties from Environment & Available settings: 00:44:38
Adding MySQL dependancy: 00:50:53
Resolving Hibernate Mapping Exception : Unknown Entity :  00:57:33
@Entity Introduction : 00:58:32
Resolving Hibernate Annotation Exception: No Identifier specified: 01:02:22
Introducing @Id: 01:03:00
Hibernate Query Generation (show_sql):  01:05:04
SQLException : No database selected  01:07:45
SQLSyntaxErrorException: Unknown Column in the field list
Introducing @Column - Hibernate mapping db columns with properties: 01:11:26
Why Session Factory is heavyweight object ? : 01:16:25
Session Vs SessionFactory : 01:26:07
Doubt Discussion : 01:34:32
Hibernate Default connection pool : 01:35:14
How to install hibernate helper plugin : 01:44:50

Just like Spring, Hibernate is also a vast framework which needs dedication and practice to learn and master. Try to create a fresh java maven project and try to practice this hibernate lesson side by side as well.

As it’s a hibernate step by step tutorial for beginners, I will be looking forward to installing the hibernate plugin and giving a demo during the end of this video. Make sure to follow the appendix if you don’t have the hibernate plugin installed.

#hibernate  #jpa  #java 

Code A Hibernate App in 100 Minutes for Beginners / Experienced
Coding  Fan

Coding Fan

1649756768

Build Full Web Application in Spring Boot Hibernate with MySQL & Docker

In This Tutorial We are going to create full stack web application in Spring Boot Hibernate With MySQL On Docker As a Backend and React as Frontend.

0:24 - Mahesh's Intro
1.25 - Getting Started
2.50 - Spring Initialiser 
4.10 - React Initialiser 
6.12 - Install MySql 
8.45 - Install TablePlus 
9.02 - Install Postman 
9.31 - Coding Part 
18.15 - Install Swagger 
21.44 - DB Connection
29.15 - Coding Part

Source Code : https://github.com/itsmaheshkariya/spring-boot-react-crud 

#spring  #react   #hibernate  #docker  #mysql 

Build Full Web Application in Spring Boot Hibernate with MySQL & Docker

SpringBlog: A Simple and Clean-design Blog System with Spring Boot

SpringBlog

SpringBlog is a very simple and clean-design blog system implemented with Spring Boot. It's one of my learning projects to explore awesome features in Spring Boot web programming. You can check my blog site for demo https://raysmond.com.

There's no demo online. Here's the screenshot of my previous blog homepage.

SpringBlog is powered by many powerful frameworks and third-party projects:

  • Spring Boot and many of Spring familiy (e.g. Spring MVC, Spring JPA, Spring Secruity and etc)
  • Hibernate + MySQL
  • HikariCP - A solid high-performance JDBC connection pool
  • Bootstrap - A very popular and responsive front-end framework
  • Pegdown - A pure-java markdown processor
  • ACE Editor - A high performance code editor which I use to write posts and code.
  • Redis - A very powerful in-memory data cache server.
  • EhCache
  • Thymeleaf (Spring MVC)

Development

Before development, please install the following service software:

Edit the spring config profile src/main/resources/application.yml according to your settings.

And start MySQL and Redis first before running the application.

# If you're using Ubuntu server

# Install MySQL
apt-get install mysql-server
service mysql start
mysql -u root -p
>> create database spring_blog;

This is a Gradle project. Make sure Gradle is installed in your machine. Try gradle -v command. Otherwise install in from http://www.gradle.org/. I recommend you import the source code into Intellij IDE to edit the code.

# Start the web application
./gradlew bootRun

Development

How to import the project into Intellij IDEA and run from the IDE?

git clone https://github.com/Raysmond/SpringBlog.git 
cd SpringBlog

bower install 
  1. Clone the project
  2. Download all dependencies
  3. Open the project in Intellij IDEA.
  4. Run SpringBlogApplication.java as Java application.
  5. Preview: http://localhost:8080 Admin: http://localhost:8080/admin , the default admin account is: admin, password: admin

Lombok is required to run the project. You can install the plugin in Intellij IDEA. Reference: https://github.com/mplushnikov/lombok-intellij-plugin

  • Build application jar ./gradlew build, then upload the distribution jar (e.g. build/libs/SpringBlog-0.1.jar) to your remote server.
  • Upload application-production.yml to your server and change it according to your server settings.
  • Run it (Java8 is a must)
java -jar SpringBlog-0.1.jar --spring.profiles.active=prod
# OR with external spring profile file
java -jar SpringBlog-0.1.jar --spring.config.location=application-production.yml

TODO

  •  Upgrade frontend framework to Bootstrap4
  •  Replace Jade with Thymeleaf(HTML)
  •  Frontend building tools, e.g. webpack
  •  Use hibernate 2nd level cache (EHCache?)
  •  Markdown preview while editing
  •  Html editor

Download Details:
Author: Raysmond
Source Code: https://github.com/Raysmond/SpringBlog
License: View license

#spring #spring-boot #java #hibernate #mysql #bootstrap 

SpringBlog: A Simple and Clean-design Blog System with Spring Boot