[JAVA] Mémo addictif de SpringBoot-JPA-Hibernate

À propos de cet article

Cet article résume ce à quoi j'étais accro lors du développement de l'application, et si trouvé, la cause et la solution. Il peut y avoir des cas où le problème est dans cet article, mais l'utilisation est incorrecte en premier lieu, ou il existe une meilleure solution.

environnement

Les problèmes rencontrés

J'obtiens une erreur lorsque je fais une association avec une clé autre que PK

Comme c'est généralement le cas avec les bases de données, il peut y avoir des problèmes avec l'implémentation d'Hibernate.

Cas d'utilisation

@Entity
class Parent {
    @Id
    Long id;
    @NatulalId
    Integer key;
    String firstName;
    String lastName;
}

@Entity
class Child {
   @Id
   Long id;
   @ManyToOne
   @JoinColumn(name = "parent_key",referencedColumnName = "key")
   Parent parent;
}

Dans l'utilisation ci-dessus où le PK recommandé par Hibernate lui-même est la clé de substitution et la clé naturelle est spécifiée par @ NaturalId, la clé est spécifiée comme Unique dans la plage des spécifications JPA, et au lieu de l'id. Si vous souhaitez fonctionner comme une clé externe. Si vous vous associez à une clé naturelle, une erreur se produira en raison de l'implication du cast lors de l'exécution de child.getParent () etc. [^ 1] [^ 1]: Cela ne semble pas arriver tout le temps, et il semble que des questions à ce sujet soient souvent publiées.

Cause

Outil de suivi officiel des problèmes HHH-7668

Solution

Rendre l'entité référencée (Parent dans ce qui précède) Sirializable. Dans cet esprit, il peut être plus sûr que toutes les entités utilisées dans Hibernate soient Sirialisables.

Un rapide coup d'œil à l'outil de suivi des problèmes montre que si vous l'associez à une colonne unique qui n'est pas PK, vous pouvez rencontrer d'autres problèmes.

2020/05/28 postscript À propos de Sirializable de l'entité

En raison des spécifications JPA, Sirializable n'est pas requis lorsqu'une entité est échangée uniquement avec DB, mais Sirializable d'une entité est requis lorsqu'elle est utilisée dans le cadre de JavaEE, par exemple en l'enregistrant en tant qu'objet dans une session HTTP. Il semble que. Considérant qu'une erreur survient dans un endroit inattendu, il semble qu'il soit souhaitable d'être Sirializable.

L'entité FetchType.Lazy génère une erreur lors de la sérialisation par Jackson

Cause

Parce que la substance de la propriété spécifiée Lazy à laquelle Jackson accède lors de la sérialisation est un proxy Hibernate

Solution

Ajoutez le plug-in Jackson pour la version Hibernate. Spring Boot dépend d'Hibernate et de Jackson par défaut, alors pourquoi n'est-ce pas inclus? [^ 2] [^ 2]: J'ai remarqué en écrivant l'article, mais il est inclus dans Spring Data REST Web MVC ... Pourquoi? Stack Overflow: Aucun sérialiseur trouvé pour ...? Stack OverFlow: Paramètres pour supprimer l'attribut Lazy dans Jackson of Spring Tout le monde traverse une période difficile.

Résolution du problème que la sérialisation Jackson de l'entité Spring JPA déclenche également Lazy Ce qui précède est une explication et une solution très simples.

Donc juste au cas où, c'est Plug-in GitHub. Le contenu n'est pas très gentil. Incidemment, Explication du contrôle de sortie par l'annotation de Jackson (solution de contournement pour la boucle infinie) introduit dans le GitHub ci-dessus.

Une erreur liée au nom de la colonne ou au nom de la table apparaît (ajout / correction 21/02/2020)

Ceci est une histoire de spécification. Ce n'est pas un bug.

Cause

~~ La stratégie de dénomination par défaut est traitée après l'annotation JPA ~~

~~ Si une annotation spécifiant un nom de table ou de colonne JPA (≒ Hibernate) est utilisée simplement à cause du problème de priorité, une erreur se produira car la conversion du nom de colonne à partir du nom de champ n'a pas été traitée. ~~

Je n'ai pas compris les spécifications. Dans Hibernate, le nom de la colonne DB est généré via une conversion en deux étapes.

  1. Générez un nom logique à partir du nom de l'entité et du nom du champ
  2. Convertissez les noms logiques en noms physiques

La valeur par défaut actuelle de Spring est

  1. Génération du nom logique
  1. Génération du nom physique --Remplacer la période par un trait de soulignement

Il est défini comme.

Étant donné que la chaîne de caractères spécifiée par @ Column ou @ Table est remplacée par ** nom logique **, si le nom du champ ou de la classe est spécifié dans le cas du chameau, le nom spécifié dans l'annotation ne doit pas être changé pour le cas du chameau. Ne doit pas être. Si un nom physique (c'est-à-dire un cas de serpent) est spécifié ici, "La table [nom de la table] contient le nom de la colonne physique [nom de la colonne] référencée par plusieurs noms de colonne logique:" (logique correspondant au nom de la colonne physique de la table) J'ai deux noms) et j'obtiens une erreur.

Solution

Si le nom de la colonne, etc. est spécifié dans l'annotation ~~ JPA, le nom doit être spécifié dans le champ avec @ Column. Je ne peux pas réduire plus que ce à quoi je m'attendais. ~~ [^ 3] [^ 3]: ~~ Je pense que cela peut être résolu en personnalisant le côté Hibernate. ~~ Lisez correctement les spécifications et les messages d'erreur. Étant donné que tous les noms physiques sont rendus inférieurs, il est préférable d'utiliser les noms de colonne et les noms de table supérieurs.

apprication.yaml



spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

(Le nom logique est utilisé comme nom physique tel quel). Cependant, Spring ImplicitNamingStrategy, que Spring utilise par défaut, utilise ImplicitNamingStrategyJpaCompliantImpl par défaut d'Hibernate presque tel quel, donc si vous utilisez le nom de propriété du cas de chameau, ce sera le nom de colonne du cas de chameau tel quel. Reportez-vous à stackoverfrow: exemple de stratégie de nommage Hibernate et sélectionnez la plus proche et ajustez-la avec des annotations. pense. Si cela ne suffit pas à détourner la stratégie d'Hibernate, vous devrez la mettre en œuvre vous-même. référence: Ajusté par la stratégie de dénomination physique Ajusté avec ImplicitNamingStrategyJpaCompliantImpl

Je veux avoir l'entité associée et la valeur réelle de la clé dans différentes propriétés

Ce n'est pas un problème, c'est une astuce. C'est un moyen pratique de créer une entité qui souhaite conserver la valeur réelle de la clé dans une propriété et suivre l'association uniquement lorsque cela est nécessaire.

Solution

Désactivez la mise à jour et l'insertion d'entités associées avec @ JoinColumn

@Entity
class Parent {
    @Id
    Long id;
    @NatulalId
    Integer key;
    String firstName;
    String lastName;
}

@Entity
class Child {
   @Id
   Long id;
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "parent_key",referencedColumnName = "key",
        insertable = false, updatable = false)
   Parent parent;
   @Column(name="parent_key")
   Integer parentKey;
}

En utilisant une classe comme celle ci-dessus, vous pouvez faire référence au parent tout en maintenant la touche directement enfoncée et empêcher l'enfant de mettre à jour le parent. Lors de la mise à jour de la référence, modifiez directement la valeur du champ clé (parentKey dans cet exemple). Cette forme fonctionne très bien pour les objets qui font référence aux données de base.

Recommended Posts

Mémo addictif de SpringBoot-JPA-Hibernate
Mémo entier
mémo docker
Mémo de Lombok
Mémo Dockerfile
Mémo Java
Mémo AWS
Mémo Dcokerfile
Memo Stream