web-dev-qa-db-fra.com

Erreur de suppression Hibernate: nombre de lignes inattendues renvoyées par la mise à jour par lot

J'ai écrit cette méthode ci-dessous qui est supposée supprimer un enregistrement de membre de la base de données. Mais lorsque je l'utilise dans ma servlet, une erreur est renvoyée.

Classe MemberDao

public static void deleteMember(Member member) {
    Session hibernateSession = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction tx = hibernateSession.beginTransaction();
    hibernateSession.delete(member);
    tx.commit();
}

Partie contrôleur

if(delete != null) {
    HttpSession httpSession = request.getSession();
    Member member = (Member) httpSession.getAttribute("member");

    MemberDao.deleteMember(member);

    nextPage = "ledenlijst.jsp";
}

Statut HTTP 500

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

Parfois, cette erreur est même générée lorsque j'essaie d'exécuter la page plusieurs fois.

org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update

Quelqu'un sait-il exactement ce qui cause ces erreurs?

20
Kid Diamond

L'erreur peut être causée par plusieurs choses. Je ne prends pas le crédit pour cela, je l'ai trouvé ici .

  1. Vider les données avant de valider l’objet peut tout effacer objet en attente de persister.
  2. Si l'objet a une clé primaire qui est générée automatiquement et que vous êtes forcer une clé assignée
  3. si vous nettoyez l'objet avant de le valider base de données.
  4. Zéro ou ID incorrect: Si vous définissez l'ID sur zéro ou quelque chose d'autre, Hibernate va essayer de mettre à jour au lieu d'insérer.
  5. Object is Stale: Hibernate met en cache les objets de la session. Si la objet a été modifié et Hibernate ne le sait pas, il le fera jette cette exception - notez la StaleStateException

Regardez aussi cette réponse de beny23 qui donne quelques astuces supplémentaires pour trouver le problème.

  • Dans votre configuration hibernate, définissez hibernate.show_sql sur true. Cela devrait vous montrer le SQL qui est exécuté et provoque le problème.
  • Définissez les niveaux de journalisation pour Spring et Hibernate sur DEBUG. Cela vous donnera à nouveau une meilleure idée de la ligne qui cause le problème.
  • Créez un test unitaire qui réplique le problème sans configurer de gestionnaire de transactions dans Spring. Cela devrait vous donner une meilleure idée de la ligne de code incriminée.
42
Ashish Jagtap

L'exception org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 Était utilisée lorsque Hibernate remarquait que l'entité qu'il voulait vider dans la base de données n'était pas exactement comme au début de la transaction.

J'ai décrit plus en détail deux cas d'utilisation différents qui m'arrivent ici .

1
Sergio Lema

Dans mon cas, cette exception a été provoquée par un mappage d'entité incorrect. Il n'y a pas eu de cascade pour la relation et l'entité enfant référencée n'a pas été enregistrée avant d'essayer de la référencer à partir du parent. En le changeant en 

    @OneToMany(cascade = CascadeType.ALL)

résolu le problème.

La meilleure façon de trouver la cause de cette exception est sûrement de définir show_sql et le niveau DEBUG pour les journaux - elle s’arrêtera juste au SQL qui a causé le problème.

1
mdziob

J'ai rencontré le même problème avec hibernate/JPA 2.1 lors de l'utilisation de memcached en tant que cache secondaire. Vous obtiendrez l'exception ci-dessus avec une exception StaleStateException. La résolution était différente de celle notée précédemment. 

J'ai remarqué que si vous avez une opération qui entrelace supprime et sélectionne (trouve) dans la même table et la même transaction, hibernate peut devenir submergé et signaler cette exception d'état obsolète. Cela ne se produirait pour nous que pendant la production, car plusieurs opérations identiques sur différentes entités se produiraient sur la même table. Vous verriez le délai d'expiration du système et le lancement d'exceptions. 

La solution consiste simplement à être plus efficace. Plutôt que d'entrelacer en boucle, essayez de résoudre les éléments à lire, de préférence en une seule opération. Effectuez ensuite la suppression dans une opération distincte. Encore une fois, tous dans la même transaction, mais ne mettez pas l'hibernation en veille avec les opérations lire/supprimer/lire/supprimer.

Ceci est beaucoup plus rapide et réduit considérablement la charge de maintenance de Hibernate. Le problème est parti. Cela se produit lorsque vous utilisez un cache secondaire et ne se produira pas car la charge sera sur la base de données pour la résolution sans cache secondaire. C'est un autre problème.

0
sagneta

c'est la solution pour mon cas, peut-être que cela vous aidera!

En réalité, il s'agissait d'un problème de conversion entre un type de champ de base de données (timestamp sur postgreSQL) et son type de propriété équivalent (Calendar) sur le fichier xib hibernate . Lorsque Hibernate a effectué cette demande de mise à jour, il n'a pas extrait la ligne car la requête avec une mauvaise valeur de calendrier de conversion . J'ai donc simplement remplacé le type de propriété "Calendrier" dans "Date" dans le fichier xib d'Hibernate et le problème a été résolu.

0
Julien

Je faisais face au même problème ... Le code fonctionnait dans l'environnement de test. Mais cela ne fonctionnait pas dans un environnement de transfert.

org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1

Le problème était que la table avait une seule entrée pour chaque clé primaire dans la table de base de données de test. Mais dans la base de données provisoire, il y avait plusieurs entrées pour la même clé primaire. (Le problème est dans la base de données de transfert, la table n'avait pas de contrainte de clé primaire et il y avait plusieurs entrées.)

Ainsi, chaque fois que l'opération de mise à jour est effectuée, elle échoue. Il tente de mettre à jour un seul enregistrement et s'attend à ce que le nombre de mises à jour soit égal à 1. Mais comme il y avait 3 enregistrements dans la table pour la même clé primaire, le nombre de mises à jour du résultat en trouve 3. Étant donné que le nombre de mises à jour prévu et le nombre de mises à jour des résultats réels ne correspondent pas , Il jette une exception et recule.

Après cela, j'ai supprimé tous les enregistrements comportant une clé primaire en double et ajouté des contraintes de clé primaire. Cela fonctionne bien.

0
ParagFlume

j'ai récemment vécu cela et ce qui s'est passé est que j'ai utilisé la méthode de mise à jour et qu'elle lançait une exception car il n'y avait aucun enregistrement existant. J'ai changé la méthode pour saveOrUpdate. Ça a marché.

0
arn-arn

J'ai eu ce problème,

J'ai vérifié mon code, il n'y avait pas de problèmes, mais lorsque j'ai vérifié mes données, j'ai découvert que j'avais deux entités avec le même identifiant!

Donc, la flush() ne pourrait pas fonctionner, car elle fonctionnait une par une pour les mises à jour par lots et elle trouvait deux lignes. Par conséquent, il n'a pas mis à jour et jeté exception, mais c'était mon problème. Je ne sais pas si cela fonctionne bien pour vous ou non!

0
Marzieh Ghadirinia