60

我有一个休眠和 JSF2 应用程序进入部署服务器并突然抛出 org.hibernate.AssertionFailure: null id 异常。我将立即提供堆栈跟踪和代码,但首先有四个重要问题:

  1. 这只发生在部署服务器上(在 Windows Sever 2008 上运行的 Jboss 和 MySql)。它不会发生在我的开发机器(在 Windoes 7 Pro 上运行的 Tomcat 和 MySql)上,也不会发生在暂存环境(在 Linux 上运行的 Jboss 和 MySql)上.)

  2. 对此进行研究,似乎人们在尝试插入对象时会出现此错误。但是当我做一个简单的查询时我得到了错误。(实际上,各种不同的查询,因为错误随机出现在几个页面上。)

  3. 错误只是偶尔发生。如果我重新启动 Jboss,它会消失,但稍后会返回。此外,它并不一致,在某些点击时它在那里,在其他点击时则不是。即使它命中,当我对页面进行简单刷新时,它也能正常返回。

  4. 我正在使用 c3p0(下面的配置)

知道发生了什么吗?

代码详情:

这发生在地址对象上。这是完整的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>

Java 类很简单:

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

}

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>

使用的版本是

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

完整的堆栈跟踪

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)
4

20 回答 20

54

例外:

org.hibernate.AssertionFailure: null id in entry(发生异常后不要刷新Session)

告诉我们会话异常发生在抛出this之前org.hibernate.AssertionFailure

确切地说,org.hibernate.AssertionFailure是在发生错误时抛出session.flush(),而不是发生错误的地方。

以上是事实,因此可能得出的结论是:某些东西可能会抑制原始异常。

因此,请寻找其他可能的错误点:Asave()saveOrUpdate()可能正在尝试使用一个字段来持久化一个实体,在该null字段中,该列是NOT NULL


提示: 为了帮助调试,请尝试session.flush()在与对象的每次交互后添加一个Session(例如session.save(obj)session.merge(obj)等),这将有望导致org.hibernate.AssertionFailure更早发生,更接近实际问题发生的位置。(当然,调试后,去掉那些session.flush()。)


就我而言,真正的异常发生在抑制异常的try/catch {}块内catch(没有重新抛出或警告我)。

于 2013-05-15T13:15:29.720 回答
16

我敢打赌并发问题,但它可能发生在不同的级别:

除了这些潜在的麻烦来源之外,我将删除 c3p0(也许只是谣言......),因为您的堆栈已经提供DataSource了与事务管理器集成的连接池。

于 2012-06-07T20:13:56.437 回答
8

@asdcjunior 已正确回答。在抛出异常之前发生了一些事情。

在那种情况下(当您为一个测试处理单个事务时,它经常发生在集成测试中 - 例如@Transaction注释)我正在调用该方法:

session.clear()

这很有帮助,因为所有“脏”对象都已从当前会话中删除,因此在执行下一次刷新时不会出现问题。

示例流程:

  • 插入分配实体(与约束的多对多关系,只能存在单个分配)-> 一切正常
  • 再次插入相同的分配实体 -> 一切正常,在这种情况下,控制器返回某种错误的请求异常,在后台 Spring 抛出 IntegrityViolationException -> 在测试中一切正常
  • 获取存储库并执行 findAll().size() 以检查已分配的计数,以确保我们只有一个分配 -> 引发了提到的异常;/ 发生了什么?在会话上仍然存在脏对象,通常会话会被破坏(控制器返回错误)但是这里我们有下一个断言来检查数据库,所以这里的解决方案是在下一个与数据库相关的方法执行之前附加 session.clear()

正确流程示例:

  • 插入分配实体
  • 插入相同的分配实体
  • session.clear()
  • 获取存储库并执行 findAll().size()

希望能帮助到你 ;)

于 2015-05-28T08:07:40.647 回答
4

您可能遇到了一些 Hibernate 错误。(我建议至少升级到 Hibernate 3.3.2.GA。)

同时,当您的 ID 可以为空时,Hibernate 会做得更好,这样 Hibernate 总是可以区分尚未持久化到数据库的新对象和已经在数据库中的对象。addressID将from的类型更改为longtoLong可能会解决该问题。

您提供的堆栈跟踪表明您在查询中看到了问题,因为您的查询强制在执行查询之前将缓冲的写入刷新到数据库并且写入失败,可能与其他人看到的相同插入问题。

于 2012-06-08T20:55:50.533 回答
4

我遇到了这个问题,我只是添加了 try catch 块,在 catch 块中我写了 seesion.clear(); 现在我可以继续将其余记录插入数据库。

于 2018-02-21T19:30:13.313 回答
2

好的,我继续根据此线程中的其他答案进行研究。但最后,由于我们面临生产截止日期,我不得不选择紧急路线。所以我没有弄清楚hibernate,而是做了这两件事:

  1. 删除了一个 jQuery 库,我使用它来获取对其中一个表单的关注。我这样做是因为我在某处读到这种类型的错误可能是由于表单发布空值而发生 - 导致空 id 下降。我怀疑 jQuery 库可能无法很好地与 PrimeFaces 配合使用,并导致某些表单出现故障。只是一种预感。

  2. 我杀死了用户和地址之间的休眠实现关系。(只需要一个,而不是一对多)并在需要时自己编写代码。幸运的是,它只显着影响了一页,所以工作量不大。

底线:我们上线了,应用程序已经运行了好几天,没有任何错误。所以这个解决方案可能并不漂亮——我并不为自己感到骄傲——但我有一个正在运行的应用程序和一个快乐的客户。

于 2012-06-11T16:34:35.953 回答
2

问题流程:

  1. 您创建一个新的瞬态实体实例(这里是地址实例)
  2. 您将其持久化到数据库中(使用保存、合并或持久化休眠会话/JPA EntityManager)
  3. 由于实体标识符是由数据库生成的,因此休眠必须触发数据库插入(它刷新会话)以检索生成的 id
  4. 插入操作触发异常(或会话中任何待处理的未刷新更改)
  5. 您捕获异常(不传播它)并恢复执行流程(此时您的会话仍然包含没有 id 的未持久实例,问题是休眠似乎将实例视为托管但实例已损坏为托管对象必须有身份证)
  6. 您到达工作单元的结尾,并且在提交当前事务之前自动刷新会话,刷新失败并出现断言失败,因为会话包含损坏的实例

您有许多可能的方法来减轻此错误:

  • 最简单的一个,就像休眠状态一样,“发生异常后不要刷新会话”,即。持久性异常后立即放弃并回滚当前事务。
  • 捕获错误后从会话中手动驱逐(JPA:分离)损坏的实例(在第 5 点,但如果错误是由另一个挂起的更改而不是实体插入本身触发的,这将是无用的)
  • 不要让数据库处理 id 生成(使用 UUID 或分布式 id 生成系统,在这种情况下,最终刷新将抛出真正的错误,阻止新实例的持久性而不是休眠断言失败)
于 2018-10-30T11:07:12.807 回答
1

org.hibernate.AssertionFailure: null id in entry(发生异常后不要刷新Session)

这只是发生在我们身上,我想我会为后代添加一些细节。事实证明,我们试图创建一个具有违反条件的重复字段的实体:

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

然而,这个异常被掩盖了,因为即使创建失败,休眠也试图提交会话。当创建失败时,没有设置 id,因此出现断言错误。在堆栈跟踪中,我们可以看到 hibernate 正在提交:

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

它应该回滚会话,而不是提交它。这原来是我们的回滚配置的问题。我们使用的是旧的 XML 配置,异常路径不正确:

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

路径不正确,LocalExceptionhibernate 没有抛出错误(或者它被埋在启动日志中)。如果您使用注释并且未指定正确的异常,也可能是这种情况:

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

一旦我们修复了休眠连接,我们就会正确地看到“重复条目”异常,并且会话正在正确回滚和关闭。

另一个问题是,当 hibernate 抛出AssertionFailure. 请参阅:https ://stackoverflow.com/a/39397836/179850

于 2016-09-08T18:35:13.473 回答
1

在以下情况下发生在我身上:

  1. 新实体被持久化。

  2. 实体配置有javax.persistence.EntityListenersjavax.persistence.PostPersist运行。

  3. PostPersist需要来自数据库的一些数据来通过STOMP. 执行org.springframework.data.repository.PagingAndSortingRepository查询。

  4. 例外。

我通过在以下内容中使用以下内容来修复它EntityListeners

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.time.Instant;
...

ThreadPoolTaskScheduler scheduler = ApplicationContextHolder.getContext().getBean(ThreadPoolTaskScheduler.class);
scheduler.schedule(() -> repository.query(), Instant.now());

其中ApplicationContextHolder定义为:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getContext() {
        return context;
    }
}
于 2020-01-17T12:04:31.513 回答
1

在我的情况下,问题是实体字段的长度参数。当我试图在其中一个字段中保存一个字符串值过长的对象时,我得到了错误。解决方案是在休眠配置中设置参数“length”的正确值。

<property name="status" type="string" length="150" not-null="false" access="field"/>

也可以使用注释 @Length 来完成,如下所示:

@Length(max=150)
private String status;

在我的情况下,休眠异常的消息非常具有误导性,堆栈跟踪也是如此。找到问题发生位置的最快方法是使用调试器跟踪您的代码并评估session.flush(); 在每个save()saveOrUpdate()方法之后。

于 2020-05-07T16:12:20.583 回答
0

这与正在执行的查询无关。这只会触发冲洗。此时 Hibernate 正在尝试为实体分配一个标识符,但似乎由于某种原因失败了。

您能否尝试更改生成器类:

<generator class="identity"/>

看看这是否有所作为。您是否还确保已部署的数据库在表上设置了正确的自动递增列?

听起来您的问题与类似。

于 2012-06-10T22:16:51.707 回答
0

更改生成器类:

<generator class="identity" />

<generator class="assigned" />
于 2015-05-07T09:38:06.503 回答
0

当我制作 session.getCurrentSession.refresh(entity) 时,我遇到了同样的错误,它对我来说更像是一个错误,而不是我的代码问题。当我尝试在测试开始时刷新实体并且该实体是在测试设置中创建的(使用 junit 的 @Before 注释)时,我在单元测试中遇到此错误。奇怪的是,我在设置中以相同的方式同时使用随机数据从同一个类创建 3 个实体,我可以刷新创建的前两个,但最后一个刷新失败。因此,例如,如果我在测试设置中创建 3 个实体用户,我可以刷新用户 1 和用户 2,但用户 3 失败。我能够通过在设置中创建实体的代码末尾添加 session.flush() 来解决此问题。我不 不会出现任何错误,我应该这样做,但我无法解释为什么需要额外的刷新。此外,即使没有刷新,我也可以确认实体实际上在测试数据库中,因为我可以在测试中查询它们,但仍然无法通过 refresh(entity) 方法。

于 2019-08-08T15:51:36.977 回答
0

就我而言,我追踪了错误并发现我没有将表的主键(即 'ID' )标记为 'Auto_Increment' AI。只需勾选 AI 复选框即可。 在此处输入图像描述

于 2021-03-14T17:32:00.167 回答
0

有时,当字符串的长度大于 DB 允许的长度时,会发生这种情况。

DataIntegrityViolationException转换为这个异常,这是休眠的一种奇怪行为。

因此,如果您Column在指定长度的实体的 String 字段上有注释并且实际值大于该长度,则会引发上述异常。

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

于 2018-07-10T14:54:15.770 回答
0

我有同样的错误。就我而言,这是因为在此异常之前我执行了异常的创建查询。异常被捕获并且不回滚捕获块中的事务。然后我在其他操作中使用这个损坏的事务,几次后我得到了同样的异常。起初我将冲洗模式设置为手动

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

然后我得到了另一个例外,它向我解释了实际上发生的事情。然后我在我的 create 方法的 catch 块中完成了事务回滚。它对我有帮助。

于 2019-01-17T06:31:14.697 回答
0

我也有同样的例外,在休眠配置文件中:

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

在对象上传递空值时,发生异常

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

我认为原因是因为 Hibernaye 将检查 'not-null' 属性,因此,删除 'not-null' 属性或将 'not-null' 设置为 'false' 将解决问题。

于 2016-11-23T03:36:02.857 回答
0

我不知道我是否迟到了,但我的问题是我正在打开一个事务并提交-> 刷新-> 在请求后关闭。但是,在这些之间,我是否有一个 nhibernate save() 运算符会自动执行此操作,在这种情况下它会抱怨。

抛出异常:

session.BeginTransaction();
model.save(entity);
session.Transaction.commit();

为我解决

model.save(entity) //this one should open transaction, save and commit/flush by itself

然而很多人说你应该同时使用,例如NHibernate: Session.Save 和 Transaction.Commit

但是由于某种原因,它现在对我有用,没有交易..

于 2021-10-14T08:41:16.623 回答
0

org.hibernate.AssertionFailure: null id in entry(发生异常后不要刷新Session)

您在使用 save 方法时遇到此错误,如果您维护用户活动的版本历史并尝试设置以下值 setCreatedBy(1); setModifiedBy(1); setCreationDate(); setChangeDate(); } 您将收到上述错误以解决此问题,您需要在表上创建以下列。

Created_By Modified_By Creation_Date Change_Date 如果您在 Update 方法解决此问题时遇到相同的错误只需将 Update() 方法更改为 merge() 方法,希望对您有所帮助。

于 2018-08-31T11:50:04.533 回答
-1

在 catch 块中回滚您的事务

于 2013-07-12T12:13:28.677 回答