it-swarm.com.de

org.hibernate.AssertionFailure: NULL-ID im Eintrag (Die Sitzung darf nicht geleert werden, wenn eine Ausnahme auftritt)

Ich habe eine Anwendung für den Ruhezustand und eine JSF2-Anwendung, die auf den Implementierungsserver geht und plötzlich eine org.hibernate.AssertionFailure-Instanz auslöst. Ich werde den Stack-Trace und den Code sofort bereitstellen, aber hier sind zunächst vier wichtige Punkte: 

  1. Dies geschieht nur auf dem Deployment Server (Jboss & MySql unter Windows Server 2008.) Dies geschieht nicht auf meinem Entwicklungscomputer (Tomcat und MySql unter Windoes 7 Pro) und auch nicht in der Staging-Umgebung (Jboss und MySql unter Linux) .) 

  2. Beim Nachforschen scheint es, dass Leute diesen Fehler erhalten, wenn sie versuchen, ein Objekt einzufügen. Ich erhalte den Fehler, wenn ich eine einfache Abfrage mache. (verschiedene Abfragen, eigentlich, da der Fehler auf mehreren Seiten zufällig auftaucht.) 

  3. Der Fehler tritt nur ab und zu auf. Wenn ich einen Jboss-Neustart durchführe, verschwindet er, aber eine Zeit später kehrt er zurück. Es ist auch nicht konsistent, bei einigen Klicks ist es vorhanden, bei anderen nicht. Selbst wenn die Seite eine einfache Aktualisierung der Seite durchführt, wird sie einwandfrei angezeigt. 

  4. Ich verwende c3p0 (config unten)

Irgendeine Idee, was los ist 

Die Code-Details: 

Dies geschieht an einem Adressobjekt. Hier ist der volle hbm: 

<?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>

Die Java-Klasse ist einfach: 

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;
}

}

Die Konfiguration von 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>

Die verwendeten Versionen sind

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

Der volle Stacktrace 

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

Die Ausnahme:

org.hibernate.AssertionFailure: NULL-ID im Eintrag (Die Sitzung darf nicht geleert werden, wenn eine Ausnahme auftritt)

Teilt uns mit, dass die Sitzungsausnahme stattgefunden hat vorher der Punkt, an dem dieses org.hibernate.AssertionFailure geworfen wird.

Um genau zu sein, wird org.hibernate.AssertionFailure ausgelöst, wenn die session.flush() stattfindet, nicht der Punkt, an dem der Fehler aufgetreten ist.

Das Obige ist eine Tatsache, daher ist eine mögliche Schlussfolgerung daraus: Etwas könnte unterdrückend die ursprüngliche Ausnahme sein.

Suchen Sie also nach other möglichen Fehlerpunkten: Eine save() oder saveOrUpdate() ist möglicherweise versucht, eine Entität mit einem null-Feld zu persistieren wobei die Spalte in der Tabelle NOT NULL ist?


TIP: Um beim Debuggen zu helfen, fügen Sie nach jeder Interaktion mit dem Session-Objekt (z. B. session.flush(), session.save(obj) usw.) eine session.merge(obj) hinzu. Dies führt hoffentlich dazu, dass org.hibernate.AssertionFailure früher passiert wo das eigentliche Problem stattfindet. (Natürlich entfernen Sie nach dem Debuggen diese session.flush().)


In meinem Fall fand die real -Exception in einem try/catch {}-Block statt, in dem die catch die Exception unterdrückt hat (hat nicht erneut geworfen oder mich darüber gewarnt).

38
acdcjunior

Ich würde für ein Parallelitätsproblem wetten, aber es kann auf verschiedenen Ebenen auftreten:

Abgesehen von diesen potenziellen Problemquellen würde ich c3p0 entfernen (vielleicht nur Gerüchte ...), da Ihr Stack DataSource bereits ein Verbindungspooling mit dem Transaktionsmanager bereitstellt.

11
Yves Martin

Der @asdcjunior hat richtig geantwortet. Etwas ist geschehen, bevor die Ausnahme ausgelöst wird.

In dieser Art von Situationen (bei Integrationsprüfungen kommt es häufig vor, wenn Sie eine einzelne Transaktion für einen Test ausführen (z. B. @Transaction-Annotation). Ich rufe die Methode auf:

session.clear()

Dies ist hilfreich, da alle 'schmutzigen' Objekte aus der aktuellen Sitzung entfernt werden. Wenn das nächste Flush ausgeführt wird, tritt das Problem nicht auf.

Beispielablauf:

  • füge die Zuweisungsentität ein (Viele-zu-Viele-Beziehung mit Einschränkung, die möglicherweise nur eine Zuweisung enthält) -> alles ok
  • füge dieselbe Zuweisung noch einmal ein -> alles in Ordnung, Controller in diesem Fall eine Art schlechte Anforderungsausnahme zurückgeben. Spring wirft die IntegrityViolationException unter die Haube -> im Test sieht alles in Ordnung aus
  • holen Sie sich das Repository und führen Sie findAll (). size () aus, um die Anzahl der vorhandenen Zuweisungen zu überprüfen, um sicherzustellen, dass nur eine einzelne Zuweisung vorliegt -> die erwähnte Ausnahme wird ausgelöst;/Was ist passiert? In der Sitzung gibt es immer noch ein fehlerhaftes Objekt. Normalerweise würde die Sitzung zerstört werden (Controller-Rückgabefehler). Hier haben wir jedoch die nächsten Assertions, die in Bezug auf die Datenbank geprüft werden sollen. Die Lösung hier ist eine zusätzliche session.clear () vor der Ausführung der nächsten db-bezogenen Methode 

Beispiel für einen korrekten Fluss:

  • fügen Sie die Zuweisungsentität ein
  • füge dieselbe Zuordnungsentität ein
  • session.clear ()
  • holen Sie sich das Repository und führen Sie findAll () aus. size ()

Ich hoffe es hilft ;)

6
Przemek Nowak

Sie schlagen wahrscheinlich einen Hibernate-Fehler. (Ich empfehle ein Upgrade auf mindestens Hibernate 3.3.2.GA.) 

In der Zwischenzeit ist Hibernate besser, wenn Ihre ID nullfähig ist, sodass Hibernate immer den Unterschied zwischen einem neuen Objekt, das noch nicht in der Datenbank gespeichert wurde, und einem bereits in der Datenbank vorhandenen unterscheiden kann. Das Ändern des Typs von addressID von long in Long wird das Problem möglicherweise umgehen. 

Die von Ihnen bereitgestellte Stack-Ablaufverfolgung zeigt, dass das Problem in einer Abfrage angezeigt wird, da die Abfrage das Speichern von gepufferten Schreibvorgängen in die Datenbank erzwingt, bevor die Abfrage ausgeführt wird und der Schreibvorgang fehlschlägt, möglicherweise mit demselben Einfügeproblem, das andere Benutzer sehen. 

3
Old Pro

Ich stand vor diesem Problem Ich füge nur try catch block hinzu und in catch block schrieb ich seesion.clear (); Jetzt kann ich mit dem Rest der Datensätze fortfahren, um sie in die Datenbank einzufügen

Herzliche Grüße: Shahid Hussain Abbasi

Problemfluss:

  1. Sie erstellen eine neue Instanz der transienten Entität (hier eine Address-Instanz)
  2. Sie bleiben in der Datenbank gespeichert (mithilfe von "Sichern", "Zusammenführen" oder "Persistieren" im Ruhezustand von Session/JPA EntityManager).
  3. Da der Entitätsbezeichner von der Datenbank im Ruhezustand generiert wird, muss die Datenbankeinfügung ausgelöst werden (die Sitzung wird geleert), um die generierte ID abzurufen
  4. Die Einfügeoperation löst eine Ausnahme aus (oder eine ausstehende nicht gelöschte Änderung in der Sitzung).
  5. Sie fangen die Ausnahme ab (ohne sie zu verbreiten) und setzen den Ausführungsablauf fort (zu diesem Zeitpunkt enthält Ihre Sitzung immer noch die nicht persistierte Instanz ohne die ID. Das Problem besteht darin, dass der Hibernate die Instanz als verwaltet betrachtet, die Instanz jedoch als verwaltetes Objekt beschädigt muss eine id haben
  6. wenn Sie das Ende Ihrer Arbeitseinheit erreicht haben und die Sitzung automatisch geleert wird, bevor die aktuelle Transaktion festgeschrieben wird, schlägt der Flush mit einem Assertionsfehler fehl, da die Sitzung eine beschädigte Instanz enthält

Sie haben viele Möglichkeiten, diesen Fehler zu mindern: 

  • Einfachste und als Ruhezustand steht "Sitzung nicht ausspülen, wenn eine Ausnahme auftritt", dh. sofort aufgeben und die aktuelle Transaktion nach einer Persistenzausnahme rückgängig machen.
  • Entfernen Sie die beschädigte Instanz manuell von der Sitzung, nachdem Sie den Fehler abgefangen haben (an Punkt 5, aber wenn der Fehler durch eine andere ausstehende Änderung anstelle der Entitätseinfügung selbst ausgelöst wurde, ist dies nutzlos.)
  • Lassen Sie nicht zu, dass die Datenbank die ID-Generierung übernimmt (verwenden Sie die UUID oder ein verteiltes ID-Generierungssystem. In diesem Fall wird der endgültige Flush den echten Fehler auslösen, der die Persistenz der neuen Instanz verhindert, anstelle eines Überbrückungsversagens).
1
Gab

Beim Erstellen von session.getCurrentSession.refresh (entity) tritt derselbe Fehler auf, der mir eher nach einem Fehler aussieht als nach einem Problem mit meinem Code. Ich erhalte diesen Fehler in einem Komponententest, wenn ich zu Beginn eines Tests versuche, eine Entität zu aktualisieren, und diese Entität im Test-Setup erstellt wird (mit @Before von junit kommentiert). Was seltsam ist, ist, dass ich 3 Entitäten aus derselben Klasse mit zufälligen Daten zur selben Zeit und auf dieselbe Weise im Setup erstelle und die ersten beiden erstellten aktualisieren kann, aber die Aktualisierung für die letzte fehlschlägt. Wenn ich zum Beispiel 3 Entitäten Benutzer im Test-Setup erstelle, kann ich Benutzer1 und Benutzer2 aktualisieren und dies schlägt für Benutzer3 fehl. Ich konnte dies beheben, indem ich session.flush () am Ende des Codes hinzufügte, der die Entität im Setup erstellt. Ich bekomme keine Fehler und sollte es tun, aber ich kann nicht erklären, warum die zusätzliche Spülung erforderlich ist. Außerdem kann ich bestätigen, dass sich die Entitäten auch ohne Flush tatsächlich in der Test-DB befinden, da ich sie im Test abfragen kann, die Aktualisierungsmethode (Entität) jedoch weiterhin fehlschlägt.

0
P Sh

Dies geschieht manchmal, wenn die Länge der Zeichenfolge größer ist als die von DB zulässige Länge.

DataIntegrityViolationException übersetzt diese Ausnahme, die durch den Ruhezustand ein seltsames Verhalten darstellt.

Wenn Sie also eine Column-Annotation für das String-Feld der Entität mit der angegebenen Länge haben und der tatsächliche Wert größer als diese Länge ist, wird die obige Ausnahme ausgelöst.

Ref: https://developer.jboss.org/thread/186341?_sscc=t

0
Nikhil Sahu

Ändern der Generatorklasse: 

<generator class="identity" />

zu

<generator class="assigned" />
0
William

org.hibernate.AssertionFailure: NULL-ID im Eintrag (Die Sitzung darf nicht geleert werden, wenn eine Ausnahme auftritt)

Das ist uns gerade passiert und ich dachte, ich würde ein paar Details für die Nachwelt hinzufügen. Es stellt sich heraus, dass wir versucht haben, eine Entität mit einem doppelten Feld zu erstellen, das gegen eine Bedingung verstößt:

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

Diese Ausnahme wurde jedoch maskiert, weil der Ruhezustand versucht hatte, die Sitzung commit zu übergeben, obwohl das Erstellen fehlgeschlagen ist. Wenn der erstellte Fehler fehlgeschlagen ist, wurde die ID nicht gesetzt, daher der Assert-Fehler. In der Stapelverfolgung konnten wir feststellen, dass der Winterschlaf begangen wurde:

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

Es hätte die Sitzung zurücksetzen sollen, ohne sie zu begehen. Dies stellte sich als Problem bei unserer Rollback-Konfiguration heraus. Wir verwenden die alten XML-Konfigurationen und der Ausnahmepfad war falsch:

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

Der LocalException-Pfad war falsch und der Ruhezustand hat keinen Fehler ausgelöst (oder er wurde in der Startprotokollspur vergraben). Dies wäre wahrscheinlich auch der Fall, wenn Sie die Annotationen verwenden und nicht die richtigen Ausnahmen angeben:

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

Nachdem wir die Verdrahtung für den Ruhezustand behoben hatten, sahen wir die Ausnahme "Eintrag duplizieren" richtig und die Sitzung wurde ordnungsgemäß zurückgesetzt und geschlossen.

Ein weiteres Problem bestand darin, dass der Hibernate, wenn die AssertionFailure geworfen wurde, eine Transaktionssperre in MySQL hielt, die dann von Hand getötet werden musste. Siehe: https://stackoverflow.com/a/39397836/179850

0
Gray

Dies hat nichts mit der gerade ausgeführten Abfrage zu tun. Dies löst nur die Spülung aus. An diesem Punkt versucht Hibernate der Entität eine Kennung zuzuweisen und scheint aus irgendeinem Grund fehlgeschlagen zu sein.

Könnten Sie versuchen, die Generatorklasse zu ändern:

<generator class="identity"/>

sehen Sie, ob das einen Unterschied macht. Haben Sie auch sichergestellt, dass für die bereitgestellte Datenbank die richtige Spalte für die automatische Erhöhung der Tabelle eingerichtet wurde?

Es klingt, als wäre Ihr Problem ähnlich wie dieses .

0
Alex Barnes

Ich habe auch die gleiche Ausnahme in der Hibernate-Konfigurationsdatei:

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

beim Übergeben eines Nullwerts am Objekt tritt eine Ausnahme auf

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

Ich denke, der Grund dafür ist, dass Hibernaye die 'not-null'-Eigenschaft überprüft. Entfernen Sie also die' not-null'-Eigenschaft oder setzen Sie 'not-null' für 'false', um das Problem zu lösen.

0
waveopera

OK, ich habe weiter nach anderen Antworten in diesem Thread gesucht. Aber am Ende, da wir einen Produktionsstermin hatten, musste ich die Notfallroutine wählen. Anstatt den Winterschlaf herauszufinden, tat ich diese beiden Dinge: 

  1. Eine jQuery-Bibliothek entfernt, mit der ich mich auf eines der Formulare konzentrierte. Ich habe dies getan, weil ich irgendwo gelesen habe, dass diese Art von Fehler auftreten kann, weil ein Formular einen Nullwert bereitstellt - die Null-ID in der Zeile verursacht wird. Ich hatte den Verdacht, dass die jQuery-Bibliothek möglicherweise nicht gut mit PrimeFaces zusammenarbeitet und zu einer Fehlfunktion der Form führt. Nur eine Ahnung. 

  2. Ich habe die durch den Ruhezustand implementierte Beziehung zwischen Benutzer und Adresse abgebrochen. (nur einer erforderlich, nicht einer zu vielen) und schrieb den Code bei Bedarf selbst. Glücklicherweise hat es nur eine Seite stark beeinflusst, daher war es nicht viel Arbeit. 

Fazit: Wir sind live gegangen und die Anwendung läuft seit mehreren Tagen fehlerfrei. Diese Lösung mag also nicht schön sein - und ich bin nicht stolz auf mich -, aber ich habe eine laufende App und einen glücklichen Kunden. 

0
Herzog

Ich hatte den gleichen Fehler. In meinem Fall lag es daran, dass vor dieser Ausnahme eine Abfrage mit Ausnahme erstellt wurde. Ausnahme wird abgefangen und die Transaktion wird nicht im catch-Block zurückgesetzt. Dann benutze ich diese kaputte Transaktion in einer anderen Operation und nach ein paar Mal bekam ich die gleiche Ausnahme. Zuerst setze ich den Spülmodus auf manuell 

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

Dann bekam ich eine weitere Ausnahme, die mir erklärte, was tatsächlich geschah. Dann habe ich ein Transaktionsrollback im catch-Block meiner create-Methode durchgeführt. Und es hat mir geholfen.

0
tomasomsk

org.hibernate.AssertionFailure: NULL-ID im Eintrag (Die Sitzung darf nicht geleert werden, wenn eine Ausnahme auftritt)

Sie erhalten diesen Fehler, während Sie die Speichermethode verwenden, wenn Sie den Versionsverlauf der Benutzeraktivität beibehalten und versuchen, die folgenden Werte festzulegen. setCreatedBy(1); setModifiedBy(1); setCreationDate(); setChangeDate();} Sie erhalten den obigen Fehler, um dieses Problem zu lösen. Sie müssen die folgenden Spalten für die Tabelle erstellen.

Created_By Modified_By Creation_Date Change_Date wenn Sie denselben Fehler während der Update-Methode erhalten, um dieses Problem zu lösen Sie müssen lediglich die Update () -Methode in die merge () -Methode ändern, die es

0
iragond