web-dev-qa-db-fra.com

org.hibernate.AssertionFailure: null id dans l'entrée (ne vide pas la session après qu'une exception se soit produite)

J'ai une application Hibernate et JSF2 qui se rend sur le serveur de déploiement et lance soudainement une exception org.hibernate.AssertionFailure: null id. Je vais fournir la trace de la pile et le code immédiatement, mais voici quatre problèmes importants en premier: 

  1. Cela ne se produit que sur le serveur de déploiement (Jboss & MySql sous Windows Server 2008). Cela ne se produit pas sur ma machine de développement (Tomcat et MySql sous Windoes 7 Pro) ni avec l'environnement de transfert (Jboss et MySql sous Linux .) 

  2. En recherchant cela, il semble que les gens obtiennent cette erreur en essayant d'insérer un objet. Mais je reçois l'erreur lorsque je fais une requête simple. (différentes requêtes, en fait, lorsque l'erreur apparaît sur plusieurs pages au hasard.) 

  3. L'erreur ne frappe que de temps en temps. Si je fais un redémarrage Jboss, il disparaîtra, mais le temps reviendra plus tard. En outre, ce n'est pas cohérent, sur certains clics c'est là, sur d'autres ce n'est pas. Même lorsque le message est affiché, lorsque je fais un simple rafraîchissement de la page, tout se passe bien. 

  4. J'utilise c3p0 (config ci-dessous)

Une idée de ce qui se passe? 

Les détails du code: 

Cela se produit sur un objet adresse. Voici le hbm complet: 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.idex.auctions.model">
<class name="Address" table="address" lazy="true">
  <id name="addressID" column="AddressID">
        <generator class="native"/>            
  </id>

  <property name="street" column="street"/> 
  <property name="city" column="city"/> 
  <property name="Zip" column="Zip"/> 
  <property name="state" column="state"/> 
  <property name="region" column="region"/> 
  <property name="country" column="country"/> 

  <many-to-one name="user" 
       class="com.idex.auctions.model.User" 
       column="userid" 
       unique="true" 
       cascade="save-update"/>
 </class> 
</hibernate-mapping>

La classe Java est simple: 

public class Address implements Serializable {
private static final long serialVersionUID = 7485582614444496906L;

private long addressID;
private String street;
private String city;
private String Zip;
private String state;
private String region;
private String country;
private User user;

public Address() {

}
public long getAddressID() {
    return addressID;
}
public void setAddressID(long addressID) {
    this.addressID = addressID;
}
public String getStreet() {
    return street;
}
public void setStreet(String street) {
    this.street = street;
}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getZip() {
    return Zip;
}
public void setZip(String Zip) {
    this.Zip = Zip;
}
public String getState() {
    return state;
}
public void setState(String state) {
    this.state = state;
}
public String getRegion() {
    return region;
}
public void setRegion(String region) {
    this.region = region;
}
public String getCountry() {
    return country;
}
public void setCountry(String country) {
    this.country = country;
}
public User getUser() {
    return user;
}
public void setUser(User user) {
    this.user = user;
}

}

La configuration c3p0: 

<property name="hibernate.c3p0.acquire_increment">1</property> 
<property name="hibernate.c3p0.idle_test_period">1000</property> 
<property name="hibernate.c3p0.max_size">20</property>  
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statements">0</property>
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

Les versions utilisées sont

hibernate3.jar

c3p0-0.9.1.2.jar

myfaces-api-2.1.4.jar

myfaces-impl-2.1.4.jar

mysql-connector-Java-5.1.20-bin.jar

La pile complète 

org.hibernate.AssertionFailure: null id in com.idex.auctions.model.Address entry 
    (don't flush the Session after an exception occurs)
org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(
                                          DefaultFlushEntityEventListener.Java:78)
org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(
                                          DefaultFlushEntityEventListener.Java:187)
org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(
                                          DefaultFlushEntityEventListener.Java:143)
org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(
                                          AbstractFlushingEventListener.Java:219)
org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(
                                          AbstractFlushingEventListener.Java:99)
org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(
                                          DefaultAutoFlushEventListener.Java:58)
org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.Java:997)
org.hibernate.impl.SessionImpl.list(SessionImpl.Java:1142)
org.hibernate.impl.QueryImpl.list(QueryImpl.Java:102)
com.idex.auctions.manager.DatabaseManager.getAllObjects(DatabaseManager.Java:464)
com.idex.auctions.ui.NavBean.gotoHome(NavBean.Java:40)
Sun.reflect.GeneratedMethodAccessor350.invoke(Unknown Source)
Sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
Java.lang.reflect.Method.invoke(Unknown Source)
javax.el.BeanELResolver.invokeMethod(BeanELResolver.Java:735)
javax.el.BeanELResolver.invoke(BeanELResolver.Java:467)
javax.el.CompositeELResolver.invoke(CompositeELResolver.Java:246)
org.Apache.el.parser.AstValue.getValue(AstValue.Java:159)
org.Apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.Java:189)
org.Apache.myfaces.view.facelets.el.ContextAwareTagValueExpression.getValue(
                                          ContextAwareTagValueExpression.Java:96)
javax.faces.component._DeltaStateHelper.eval(_DeltaStateHelper.Java:246)
javax.faces.component.UIOutcomeTarget.getOutcome(UIOutcomeTarget.Java:50)
org.Apache.myfaces.shared.renderkit.html.HtmlRendererUtils.getOutcomeTargetHref(
                                          HtmlRendererUtils.Java:1542)
org.Apache.myfaces.shared.renderkit.html.HtmlLinkRendererBase.renderOutcomeLinkStart(
                                          HtmlLinkRendererBase.Java:908)
org.Apache.myfaces.shared.renderkit.html.HtmlLinkRendererBase.encodeBegin(
                                          HtmlLinkRendererBase.Java:143)
javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.Java:502)
javax.faces.component.UIComponent.encodeAll(UIComponent.Java:744)
javax.faces.component.UIComponent.encodeAll(UIComponent.Java:758)
javax.faces.component.UIComponent.encodeAll(UIComponent.Java:758)
org.Apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(
                                    FaceletViewDeclarationLanguage.Java:1900)
org.Apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.Java:285)
com.ocpsoft.pretty.faces.application.PrettyViewHandler.renderView(
                                    PrettyViewHandler.Java:163)
javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.Java:59)
org.Apache.myfaces.tomahawk.application.ResourceViewHandlerWrapper.renderView(
                                    ResourceViewHandlerWrapper.Java:93)
com.idex.auctions.ui.CustomViewHandler.renderView(CustomViewHandler.Java:98)
org.Apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.Java:115)
org.Apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.Java:241)
javax.faces.webapp.FacesServlet.service(FacesServlet.Java:199)
com.ocpsoft.pretty.PrettyFilter.doFilter(PrettyFilter.Java:126)
com.ocpsoft.pretty.PrettyFilter.doFilter(PrettyFilter.Java:118)
37
Herzog

Je parierais pour un problème de concurrence, mais cela peut se produire à différents niveaux:

  • une session d'hibernation peut être partagée entre différents utilisateurs si le modèle classique "session ouverte en vue" n'est pas correctement implémenté
  • une entité est partagée entre deux sessions utilisateur à cause de paramètres de cache inappropriés hibernate
  • une connexion JDBC est partagée entre deux sessions hibernate différentes (moins probable)

Outre ces sources potentielles de problèmes, je supprimerais c3p0 (peut-être simplement des rumeurs ...) car votre pile fournit déjà DataSource avec la mise en commun des connexions intégrée au gestionnaire de transactions.

11
Yves Martin

Le @asdcjunior a répondu correctement. Quelque chose s'est passé avant que l'exception soit levée.

Dans ce genre de situation (cela se produit souvent lors de tests d'intégration lorsque vous traitez avec une transaction unique pour un test - par exemple, l'annotation @Transaction), j'appelle la méthode:

session.clear()

Cela aide car tous les objets "sales" sont supprimés de la session en cours. Ainsi, lors de l'exécution du rinçage suivant, le problème n'apparaît pas.

Exemple de flux:

  • insérer l'entité d'affectation (relation plusieurs-à-plusieurs avec une contrainte pouvant exister seulement une affectation) -> tout va bien
  • insère la même entité d'affectation une fois de plus -> tout va bien, le contrôleur renvoie dans ce cas une sorte d'exception de mauvaise demande, sous le capot Spring lève l'IntegrityViolationException -> dans le test, tout semble correct
  • récupérez le référentiel et exécutez findAll (). size () pour vérifier le nombre d'existences assignées afin de vous assurer que nous n'avons qu'une seule affectation -> l'exception mentionnée est levée;/que s'est-il passé? sur la session, il y a toujours un objet sale, normalement, la session serait détruite (erreur de renvoi du contrôleur), mais nous avons ici les assertions suivantes à vérifier concernant la base de données. La solution est donc ici session.clear () avant la prochaine exécution de méthode liée à la base 

Exemple de flux correct:

  • insérer l'entité d'affectation
  • insérer la même entité d'affectation
  • session.clear ()
  • récupérez le référentiel et exécutez findAll (). size ()

J'espère que ça aide ;)

6
Przemek Nowak

Vous rencontrez probablement un bogue Hibernate. (Je vous recommande de mettre à niveau vers au moins Hibernate 3.3.2.GA.) 

Pendant ce temps, Hibernate fait mieux lorsque votre identifiant peut être annulé, afin qu’Hibernate puisse toujours faire la différence entre un nouvel objet qui n’a pas encore été conservé dans la base de données et un autre qui est déjà dans la base de données. Changer le type de addressID de long à Long résoudra probablement le problème. 

La trace de pile que vous avez fournie montre que vous voyez le problème sur une requête, car elle oblige les écritures mises en tampon à être vidées dans la base de données avant que la requête ne soit exécutée et que l'écriture échoue, probablement avec le même problème d'insertion que d'autres personnes voient. 

3
Old Pro

Je faisais face à ce problème Je viens d’ajouter try catch et dans catch block j’ai écrit seeion.clear (); Maintenant je peux continuer avec le reste des enregistrements à insérer dans la base

Cordialement, Shahid Hussain Abbasi

2
Shahid Hussain Abbasi

Flux de problème:

  1. Vous créez une nouvelle instance d'entité transitoire (ici une instance d'adresse)
  2. Vous le conservez dans la base de données (en utilisant save, fusionner ou persister dans hibernate Session/JPA EntityManager)
  3. Comme l'identifiant d'entité est généré par la base de données, hibernate doit déclencher l'insertion de la base de données (elle vide la session) pour récupérer l'identifiant généré.
  4. L'opération d'insertion déclenche une exception (ou toute modification non vidée en attente dans la session)
  5. Vous attrapez l'exception (sans la propager) et reprenez le flux d'exécution (à ce stade, votre session contient toujours l'instance non analysée sans l'identifiant. Le problème est que hibernate semble considérer l'instance comme gérée, mais qu'elle est corrompue en tant qu'objet géré. doit avoir un identifiant)
  6. vous atteignez la fin de votre unité de travail et la session est automatiquement vidée avant que la transaction en cours ne soit validée; le vidage échoue avec un échec d'assertion, car la session contient une instance corrompue

Vous avez plusieurs façons possibles d'atténuer cette erreur: 

  • Le plus simple et en veille prolongée "ne pas vider la session après qu'une exception se soit produite" c'est-à-dire. abandonner immédiatement et annuler la transaction en cours après une exception de persistance.
  • Expulser manuellement (JPA: détacher) l'instance corrompue de la session après avoir détecté l'erreur (au point 5, mais si l'erreur a été déclenchée par une autre modification en attente à la place de l'entité insérée, elle sera inutile)
  • Ne laissez pas la base de données gérer la génération d'identifiant (utilisez UUID ou un système de génération d'identifiant distribué, dans ce cas, le vidage final générera l'erreur réelle empêchant la persistance de la nouvelle instance au lieu d'un échec d'assertion hibernate)
1
Gab

Parfois, cela se produit lorsque la longueur de la chaîne est supérieure à celle autorisée par la base de données.

DataIntegrityViolationException traduit cette exception qui est un comportement étrange de la part de Hibernate.

Ainsi, si vous avez l'annotation Column dans le champ String de l'entité avec la longueur spécifiée et que la valeur réelle est supérieure à cette longueur, l'exception ci-dessus est levée.

Réf.: https://developer.jboss.org/thread/186341?_sscc=t

0
Nikhil Sahu

Changer la classe du générateur: 

<generator class="identity" />

à

<generator class="assigned" />
0
William

org.hibernate.AssertionFailure: null id dans l'entrée (ne pas vider la session après qu'une exception se soit produite)

Cela vient de nous arriver et je pensais ajouter quelques détails pour la postérité. Il s'avère que nous essayions de créer une entité avec un champ en double qui violait une condition:

Caused by: org.hibernate.exception.ConstraintViolationException: Duplicate entry '' for key
'Index_schools_name'

Cette exception était cependant masquée car hibernate essayait de commit la session même si la création avait échoué. Lorsque la création a échoué, l'id n'a pas été défini, d'où l'erreur d'assert. Dans la trace de la pile, nous pouvions voir qu'Hibernate était en train de commettre:

at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit
(HibernateTransactionManager.Java:480)

Il aurait dû annuler la session et ne pas l’engager. Cela s'est avéré être un problème avec notre configuration de restauration. Nous utilisons les anciennes configurations XML et le chemin d’exception était incorrect:

<prop key="create*">PROPAGATION_REQUIRED,-org.x.y.LocalException</prop>

Le chemin LocalException était incorrect et hibernate n'a pas généré d'erreur (ou il était enterré dans le journal de démarrage). Ce serait probablement aussi le cas si vous utilisez les annotations et ne spécifiez pas la ou les bonnes exceptions:

// NOTE: that the rollbackFor exception should match the throws (or be a subclass)
@Transactional(rollbackFor = LocalException.class)
public void create(Entity entity) throws AnotherException {

Une fois que nous avons corrigé notre câblage d'hibernation, nous avons correctement détecté l'exception "entrée en double" et la session a été correctement annulée et fermée.

Un problème supplémentaire à cela est que lorsque Hibernate lançait la variable AssertionFailure, elle détenait un verrou de transaction dans MySQL qui devait ensuite être tué manuellement. Voir: https://stackoverflow.com/a/39397836/179850

0
Gray

Cela n'a rien à voir avec la requête en cours d'exécution. Cela déclenche simplement la couleur. À ce stade, Hibernate tente d'attribuer un identifiant à l'entité et semble avoir échoué pour une raison quelconque.

Pourriez-vous essayer de changer la classe du générateur:

<generator class="identity"/>

voyez si cela fait une différence. Assurez-vous également que la base de données que vous avez déployée dispose de la colonne d'incrémentation automatique correcte configurée sur la table?

Il semble que votre problème ressemble à celui-ci .

0
Alex Barnes

J'ai la même exception aussi, dans le fichier de configuration hibernate:

<property name="operateType" type="Java.lang.Integer">
        <column name="operate_type" not-null="true" />
 </property>

lorsque passe la valeur null à l'objet, exception se produit

 "org.hibernate.AssertionFailure: null id in com.idex.auctions.model.Address entry",

Je pense que la raison pour laquelle Hibernaye va vérifier la propriété 'not-null', alors, supprimer la propriété 'not-null' ou définir 'not-null' pour 'false' va résoudre le problème.

0
waveopera

OK, j'ai continué mes recherches basées entre autres sur d'autres réponses de ce fil. Mais au bout du compte, nous étions devant un délai de production et je devais choisir la route d'urgence. Donc, au lieu de penser à l'hibernation, j'ai fait ces deux choses: 

  1. Suppression d'une bibliothèque jQuery que j'utilisais pour me concentrer sur l'un des formulaires. Je l’ai fait parce que j’avais lu quelque part que ce type de bogue pouvait survenir en raison de la publication d’une valeur NULL par un formulaire, ce qui entraînait l’identification NULL sur la ligne. Je soupçonnais que la bibliothèque jQuery ne fonctionnerait pas bien avec PrimeFaces et causerait des dysfonctionnements. Juste une intuition. 

  2. J'ai tué la relation mise en place par hibernate que j'avais entre utilisateur et adresse. (un seul requis, pas un à plusieurs) et a écrit le code moi-même en cas de besoin. Heureusement, cela n'a affecté qu'une page de manière significative, donc cela n'a pas demandé beaucoup de travail. 

En bout de ligne: nous sommes entrés en ligne et l'application fonctionne depuis plusieurs jours sans erreur. Donc, cette solution peut ne pas être jolie - et je ne suis pas fière de moi -, mais j'ai une application en cours d'exécution et un client heureux. 

0
Herzog

J'ai eu la même erreur. Dans mon cas, c'était parce qu'avant cette exception, j'exécutais une requête create avec exception. L'exception est interceptée et n'annule pas la transaction dans le bloc catch. Ensuite, j'utilise cette transaction cassée dans une autre opération et après quelques temps, j'ai la même exception. Au début, je règle le mode flush sur manuel 

public final Session getCurrentSession()  
{
    Session session = sessionFactory.getCurrentSession();
    session.setFlushMode(FlushMode.MANUAL);
    return session;
}

Ensuite, j'ai eu une autre exception, qui m'a expliqué ce qui s'est passé en fait. Ensuite, j'ai effectué l'annulation de transaction dans le bloc catch de ma méthode create. Et ça m'a aidé.

0
tomasomsk

org.hibernate.AssertionFailure: null id dans l'entrée (ne vide pas la session après qu'une exception se soit produite)

Vous obtenez cette erreur lorsque vous utilisez la méthode de sauvegarde, si vous conservez l’historique des versions de l’activité de l’utilisateur et essayez de définir les valeurs suivantes setCreatedBy(1); setModifiedBy(1); setCreationDate(); setChangeDate();} Vous obtiendrez l'erreur ci-dessus pour résoudre ce problème, vous devez créer les colonnes suivantes sur la table.

Created_By Modified_By Creation_Date Change_Date Si vous obtenez la même erreur en mettant à jour la méthode Update pour résoudre ce problème, il vous suffit de modifier la méthode Update () pour fusionner la méthode (). Cette J'espère vous avoir aidé.

0
iragond