web-dev-qa-db-fra.com

Hibernate - La mise à jour par lot a renvoyé un nombre inattendu de lignes à partir de la mise à jour: 0 nombre réel de lignes: 0 attendu: 1

Je reçois l'erreur d'hibernation suivante. Je suis capable d'identifier la fonction qui cause le problème. Malheureusement, il y a plusieurs appels à la base de données dans la fonction. Je ne parviens pas à trouver la ligne à l'origine du problème, car hibernate vide la session à la fin de la transaction. L'erreur d'hibernation mentionnée ci-dessous ressemble à une erreur générale. Il ne mentionne même pas quel haricot est à l'origine du problème. Quelqu'un au courant de cette erreur d'hibernation?

org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
        at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.Java:93)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.Java:79)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.Java:58)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.Java:195)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.Java:235)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.Java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.Java:297)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.Java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.Java:985)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.Java:333)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.Java:106)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.Java:584)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransacti
onManager.Java:500)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManag
er.Java:473)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.doCommitTransactionAfterReturning(Transaction
AspectSupport.Java:267)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:176)
120
Sujee

Sans code ni mappages pour vos transactions, il sera pratiquement impossible d'examiner le problème.

Toutefois, pour mieux comprendre la cause du problème, procédez comme suit:

  • 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.

J'espère que ça t'as aidé.

50
beny23

J'ai eu la même exception lors de la suppression d'un enregistrement par ID qui n'existe pas du tout. Vérifiez donc que l’enregistrement que vous mettez à jour/supprime existe bien dans la base de données.

60
shreyas

Solution: Dans le fichier de mappage Hibernate de la propriété id, si vous utilisez une classe de générateur, vous ne devez pas définir explicitement cette valeur à l'aide de la méthode setter.

Si vous définissez explicitement la valeur de la propriété Id, l'erreur ci-dessus sera générée. Cochez cette option pour éviter cette erreur. ou C'est une erreur lorsque vous mentionnez dans le fichier de mappage le générateur de champ = "natif" ou "incrémental" et dans votre base de données, la table mappée n'est pas auto_incrémentée Solution: Accédez à votre base de données et mettez à jour votre table pour définir auto_increment

47
Rēda Biramanē

Cela m'est arrivé une fois par accident lorsque j'attribuais des identifiants spécifiques à certains objets (tests), puis que j'essayais de les sauvegarder dans la base de données. Le problème était qu’il existait dans la base de données une stratégie spécifique pour la configuration des ID des objets. Il suffit de ne pas le faire assigner un ID si vous avez une politique au niveau d'Hibernate.

17
Christian Adam

Dans mon cas, je suis arrivé à cette exception dans deux cas similaires:

  • Dans une méthode annotée avec @Transactional, j'ai eu un appel vers un autre service (avec de longs délais de réponse). La méthode met à jour certaines propriétés de l'entité (après la méthode, l'entité existe toujours dans la base de données). Si l'utilisateur demande deux fois la méthode (car il pense que cela ne fonctionne pas la première fois) lorsqu'il quitte la méthode transactionnelle une deuxième fois, Hibernate tente de mettre à jour une entité qui a déjà changé d'état depuis le début de la transaction. Lorsque Hibernate recherche une entité dans un état et trouve la même entité mais qu'elle a déjà été modifiée par la première demande, il lève une exception car il ne peut pas mettre à jour l'entité. C'est comme un conflit dans GIT.
  • J'ai eu des demandes automatiques (pour surveiller la plate-forme) qui mettent à jour une entité (et la restauration manuelle quelques secondes plus tard). Mais cette plate-forme est déjà utilisée par une équipe de test. Lorsqu'un testeur effectue un test dans la même entité que les demandes automatiques (dans le même centième de milliseconde), j'obtiens l'exception. Comme dans le cas précédent, lors de la sortie de la deuxième transaction, l'entité précédemment extraite avait déjà changé.

Conclusion: dans mon cas, ce n'était pas un problème qui peut être trouvé dans le code. Cette exception est levée lorsque Hibernate constate que l'entité extraite de la base de données a été modifiée pour la première fois au cours de la transaction en cours , de sorte qu'elle ne peut pas la vider dans la base de données. Hibernate ne sait pas quelle est la version correcte de l'entité: celle que la transaction en cours récupère au début; ou celui déjà stocké dans la base de données.

Solution: pour résoudre le problème, vous devrez jouer avec le Hibernate LockMode afin de trouver celui qui correspond le mieux à vos besoins.

9
Sergio Lema

Cela peut se produire lorsque le ou les déclencheurs exécutent des requêtes DML (modification de données) supplémentaires qui affectent le nombre de lignes. Ma solution a été d'ajouter ce qui suit en haut de ma gâchette:

SET NOCOUNT ON;
9
Mr. TA

Je viens de rencontrer ce problème et de découvrir que je supprimais un enregistrement et que je tentais de le mettre à jour par la suite dans une transaction Hibernate.

7
Julius

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 entrée unique 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 aucune 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 enregistrement et espère obtenir un nombre de mises à jour é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 contenant une clé primaire en double et ajouté des contraintes de clé primaire. Cela fonctionne bien.

Hibernate - Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1

nombre actuel de lignes: 0 // signifie qu'aucun enregistrement à mettre à jour
update: 0 // signifie qu'aucun enregistrement n'a été trouvé, donc rien n'est mis à jour
attendu: 1 // signifie attendu au moins 1 enregistrement avec clé dans la table db.

Ici, le problème est que la requête essayant de mettre à jour un enregistrement pour une clé, mais hibernate n'a trouvé aucun enregistrement avec la clé.

6
ParagFlume

J'ai rencontré ce problème où nous avions une relation un-plusieurs.

Dans le fichier de mappage hibernate hbm pour maître, pour un objet avec une disposition de type définie, ajouté cascade="save-update" et tout s'est bien déroulé.

Sans cela, par défaut, hibernate essaie de mettre à jour pour un enregistrement inexistant et, ce faisant, insère à la place.

5
Shiv

Comme Julius indique que cela se produit lorsqu'une mise à jour se produit sur un objet dont les enfants sont supprimés. (Probablement parce qu'il y avait un besoin de mise à jour pour l'objet Père entier et que nous préférons parfois supprimer les enfants et les réinsérer sur le Père (nouveau, ancien, cela n'a pas d'importance), ainsi que toute autre mise à jour que le père pourrait avoir sur l'un des éléments suivants. Pour que cela fonctionne, supprimez les enfants (dans une transaction) en appelant childrenList.clear() (ne parcourez pas les enfants et supprimez-en chacun avec une fonction childDAO.delete(childrenList.get(i).delete())) et en définissant @OneToMany(cascade = CascadeType.XXX ,orphanRemoval=true) sur le côté de l'objet père. Mettez ensuite à jour le père (fatherDAO.update (père)). (Répétez l'opération pour chaque objet père). Le résultat est que les enfants perdent leur lien avec leur père, puis ils sont supprimés comme orphelins par le cadre.

4

Cela peut également arriver lorsque vous essayez de UPDATE a PRIMARY KEY.

3
Marcel

j'ai eu le même problème et j'ai vérifié que cela pouvait se produire à cause de l'incrémentation automatique de la clé primaire. Pour résoudre ce problème, n'insérez pas de valeur dans l'incrémentation automatique. Insérer des données sans la clé primaire.

3
MacDaddy

Cela m'est aussi arrivé, parce que mon identifiant était Long et que la vue affichait la valeur 0. Lorsque j'ai essayé de sauvegarder dans la base de données, j'ai eu cette erreur et je l'ai corrigé en définissant l'identifiant sur null.

2
Roberto Rodriguez

Une autre façon d'obtenir cette erreur est si vous avez un élément null dans une collection.

2
Bryan Pugh

cela se produit lorsque vous essayez de supprimer le même objet, puis de le mettre à jour, utilisez ceci après la suppression

session.clear ();

2
Sumit Singh

Après avoir lu toutes les réponses, n’a trouvé personne qui parle d’attribut inverse d’hibernation.

À mon avis, vous devriez également vérifier dans vos relations la cartographie si clé inverse clé Word est correctement configuré. Inverse le mot-clé est créé pour définir de quel côté est le propriétaire pour maintenir la relation. La procédure de mise à jour et d’insertion varie en fonction de cet attribut.

Supposons que nous ayons deux tables:

principal_table, middle_table

avec une relation de n à plusieurs. Les classes de mappage hiberntate sont respectivement Principal et Moyen.

Donc, la classe Principal a un ensemble d'objets Milie. Le fichier de mappage xml devrait ressembler à ceci:

<hibernate-mapping>
    <class name="path.to.class.Principal" table="principal_table" ...>
    ...
    <set name="middleObjects" table="middle_table" inverse="true" fetch="select">
        <key>
            <column name="PRINCIPAL_ID" not-null="true" />
        </key>
        <one-to-many class="path.to.class.Middel" />
    </set>
    ...

Comme inverse est défini sur "true", cela signifie que la classe "intermédiaire" est le propriétaire de la relation. Par conséquent, la classe principale va NOT UPDATE la relation.

La procédure de mise à jour pourrait donc être mise en œuvre de la manière suivante:

session.beginTransaction();

Principal principal = new Principal();
principal.setSomething("1");
principal.setSomethingElse("2");


Middle middleObject = new Middle();
middleObject.setSomething("1");

middleObject.setPrincipal(principal);
principal.getMiddleObjects().add(middleObject);

session.saveOrUpdate(principal);
session.saveOrUpdate(middleObject); // NOTICE: you will need to save it manually

session.getTransaction().commit();

Cela a fonctionné pour moi, mais vous pouvez suggérer quelques éditions afin d'améliorer la solution. De cette façon, nous allons tous apprendre.

1
Luis Teijon

J'ai aussi rencontré le même défi. Dans mon cas, je mettais à jour un objet qui n'existait même pas, en utilisant hibernateTemplate.

En fait, dans mon application, je devais mettre à jour un objet de base de données. Et lors de la mise à jour de ses valeurs, j'ai également mis à jour son ID par erreur et je suis allé de l'avant pour le mettre à jour et je suis tombé sur ladite erreur.

J'utilise hibernateTemplate pour les opérations CRUD.

1
Kuldeep Verma

J'ai rencontré ce problème lorsque je débutais et que je validais manuellement des transactions à l'intérieur de la méthode annotée comme @Transactional. J'ai résolu le problème en détectant si une transaction active existait déjà.

//Detect underlying transaction
if (session.getTransaction() != null && session.getTransaction().isActive()) {
    myTransaction = session.getTransaction();
    preExistingTransaction = true;
} else {
    myTransaction = session.beginTransaction();
}

Ensuite, j'ai autorisé Spring à gérer la validation de la transaction.

private void finishTransaction() {
    if (!preExistingTransaction) {
        try {
            tx.commit();
        } catch (HibernateException he) {
            if (tx != null) {
                tx.rollback();
            }
            log.error(he);
        } finally {
            if (newSessionOpened) {
                SessionFactoryUtils.closeSession(session);
                newSessionOpened = false;
                maxResults = 0;
            }
        }
    }
}
1
Gibado

Cela se produit lorsque vous avez déclaré le bean géré JSF comme

@RequestScoped;

quand faut-il déclarer que

@SessionScoped;

Cordialement;

1
John Lopez

J'ai eu cette erreur lorsque j'ai essayé de mettre à jour un objet avec un identifiant qui n'existait pas dans la base de données. La raison de mon erreur est que j’avais assigné manuellement une propriété avec le nom 'id' à la représentation JSON client de l’objet, puis lors de la désérialisation de l’objet côté serveur, cette propriété 'id' écrasait la variable d’instance ( également appelé 'id') qu'Hibernate était censé générer. Faites donc attention à ne pas nommer les collisions si vous utilisez Hibernate pour générer des identifiants.

1
Soggiorno

En fait, cela m’arrive quand je n’ai pas stocké l’objet comme variable de référence. en classe d'entité. Comme ce code: ses.get(InsurancePolicy.class, 101); Après cela, j'ai stocké l'objet dans la variable de référence de l'entité afin que le problème soit résolu pour moi. policy=(InsurancePolicy)ses.get(InsurancePolicy.class, 101); Après cela, j'ai mis à jour l'objet et tout a bien fonctionné.

0
karan bainade

Dans mon cas, il y avait un problème avec la base de données car l'un des processus stockés consommait tout le processeur, ce qui entraînait des temps de réponse de la base de données élevés. Une fois que ce problème a été tué, il est résolu.

0
Amit

Un des cas

SessionFactory sf=new Configuration().configure().buildSessionFactory();
Session session=sf.openSession();

UserDetails user=new UserDetails();

session.beginTransaction();
user.setUserName("update user agian");
user.setUserId(12);
session.saveOrUpdate(user);
session.getTransaction().commit();
System.out.println("user::"+user.getUserName());

sf.close();
0
vootla561

Peu de façons j'ai débogué cette erreur:

  1. Comme suggéré dans la réponse acceptée, activez show sql.
  2. J'ai trouvé qu'il y avait un problème avec la configuration de l'id dans le hibernate sql.
  3. Constaté qu'il me manquait @GeneratedValue (strategy = GenerationType.IDENTITY)
0
Durja Arai

J'ai eu cette erreur parce que j'ai mappé par erreur la colonne ID en utilisant Id(x => x.Id, "id").GeneratedBy.**Assigned**();

Problème résolu en utilisant Id(x => x.Id, "id").GeneratedBy.**Identity**();

0
roylac

Cela m’arrive car il me manque une déclaration d’identité dans la classe de haricot.

0
Ganesh Giri

Cela se produit si vous modifiez quelque chose dans un ensemble de données à l'aide d'une requête SQL native, mais qu'un objet persistant pour le même ensemble de données est présent dans le cache de session. Utilisez session.evict (votreObjet);

0
abhi

Je faisais face à cette exception et l'hibernation fonctionnait bien. J'ai essayé d'insérer manuellement un enregistrement à l'aide de pgAdmin. Ici, le problème est devenu évident. La requête d'insertion SQL renvoie 0 insert. et il existe une fonction de déclencheur qui cause ce problème car il renvoie null. il ne me reste donc plus qu'à le régler pour qu'il retourne neuf. et finalement j'ai résolu le problème.

espérons que cela aide n'importe quel corps.

0
kamel2005

Hibernate met en cache des objets de la session. Si l'objet est accédé et modifié par plus d'un utilisateur, alors org.hibernate.StaleStateException peut être levé. Il peut être résolu avec la méthode de fusion/actualisation d’entités avant d’enregistrer ou d’utiliser un verrou. Plus d'infos: http://Java-fp.blogspot.lt/2011/09/orghibernatestalestateexception-batch.html

0
Justas

J'ai reçu le même message. Après avoir recherché une source liée au code, il m’a été révélé que l’exécution de l’application sur une machine locale interfère avec l’étape de développement, car elle partage le même DB. Ainsi, parfois, un serveur a déjà supprimé une entrée alors que l'autre voulait faire de même.

0
YumikoTanaka

Dans notre cas, nous avons enfin découvert la cause première de StaleStateException.

En fait, nous supprimions la ligne deux fois en une seule session d'hibernation. Auparavant, nous utilisions ojdbc6 lib, et c’était acceptable dans cette version.

Mais lorsque nous sommes passés à odjc7 ou ojdbc8, la suppression d'enregistrements à deux reprises générait une exception. Il y avait un bug dans notre code où nous supprimions deux fois, mais ce n'était pas évident dans ojdbc6.

Nous avons pu reproduire avec ce morceau de code:

Detail detail = getDetail(Long.valueOf(1396451));
session.delete(detail);
session.flush();
session.delete(detail);
session.flush();

À la première chasse, l'hibernation va et apporte des modifications à la base de données. Au cours de la deuxième chasse, le mode veille prolongée compare l'objet de la session à l'enregistrement de la table réelle, mais ne peut en trouver un, d'où l'exception.

0
Sandeep Khantwal