当前位置: 首页 > 知识库问答 >
问题:

升级到Hibernate 4.1.3 Final后刷新时引发NullPointerException

侯令雪
2023-03-14

我刚刚完成了从Hibernate 3.6到4.1.3 Final的升级,起初一切似乎都很顺利。然而,我的一位同事最近在一个场景中测试了这个问题,他从Hibernate中抛出了一个空指针(在我们升级到完全相同的DB之前,没有抛出这个异常)。这是一个不可思议的奇怪场景。我们有一个名为BlogPost的实体,如下所示,它扩展了一些映射的超类(我也包括了这些超类):

@Entity
@Table(name = "blog_post")
public class BlogPost extends CommunityModelObject implements HasFeedPost {

    @Lob
    private String title;
    @Lob
    private String content;
    @Enumerated
    @Column(nullable = false)
    private CBlogPost.Status status = CBlogPost.Status.UNPUBLISHED;
    // Reference to the feed post that indicates that this blog post has been published
    @OneToOne
    @JoinColumn(name = "feed_post_id")
    private FeedPost feedPost;
    @ManyToOne
    @JoinColumn(name = "posted_by_employee_id")
    private Employee postedBy;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public CBlogPost.Status getStatus() {
        return status;
    }

    public void setStatus(CBlogPost.Status status) {
        this.status = status;
    }

    @Override
    public FeedPost getFeedPost() {
        return feedPost;
    }

    @Override
    public void setFeedPost(FeedPost feedPost) {
        this.feedPost = feedPost;
    }

    public Employee getPostedBy() {
        return postedBy;
    }

    public void setPostedBy(Employee postedBy) {
        this.postedBy = postedBy;
    }
}


@Filter(name = "tenantFilter", condition = "(tenant_id = :tenantId or tenant_id is null)")
@MappedSuperclass
public abstract class CommunityModelObject extends ModelObject {

    @IndexedEmbedded(prefix = "tenant", indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
    @ManyToOne
    @JoinColumn(name = "tenant_id")
    protected Tenant tenant;

    public Tenant getTenant() {
        return tenant;
    }

    public void setTenant(Tenant tenant) {
        this.tenant = tenant;
    }

    /**
     * If the Tenant is null then it can be accessed / viewed by the entire "community" / user base
     */
    public boolean isCommunityObject() {
        return tenant == null;
    }
}


@MappedSuperclass
public abstract class ModelObject extends BaseModelObject {

    @Id
    @GeneratedValue
    private Long id;

    @Override
    public long getId() {
        return (id == null ? 0 : id);
    }

    public void setId(long id) {
        this.id = (id == 0 ? null : id);
    }
}


@MappedSuperclass
public abstract class BaseModelObject implements java.io.Serializable {

    // This annotation ensures that a column is not associated with this member (simply omitting the @Column annotation is not enough since
    // that annotation is completely optional)
    @Transient
    private boolean doNotAutoUpdateDateUpdated = false;

    @Version
    protected int version;
    @Column(name = "date_created")
    protected Date dateCreated;
    @Column(name = "date_updated")
    protected Date dateUpdated;

    public abstract long getId();

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public Date getDateCreated() {
        return dateCreated;
    }

    public Date getDateUpdated() {
        return dateUpdated;
    }

    /**
     * This will set the dateUpdated to whatever is passed through and it will cause the auto update (pre-update) to NOT occur
     *
     * @param dateUpdated
     */
    public void setDateUpdated(Date dateUpdated) {
        doNotAutoUpdateDateUpdated = true;
        this.dateUpdated = dateUpdated;
    }

    public void touch() {
        // By setting date updated to null this triggers an update which results in onUpdate being called and the nett
        // result is dateUpdated = new Date()
        dateUpdated = null;
    }

    @PrePersist
    protected void onCreate() {
        dateCreated = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
        if (!doNotAutoUpdateDateUpdated) {
            dateUpdated = new Date();
        }
    }

    @Override
    public boolean equals(Object obj) {
        long id = getId();

        if (id == 0) {
            return this == obj;
        }
        //Use Hibernate.getClass() because objects might be proxies
        return obj != null &&
                obj instanceof BaseModelObject &&
                Hibernate.getClass(this) == Hibernate.getClass(obj) &&
                getId() == ((BaseModelObject)obj).getId();
    }

    @Override
    public int hashCode() {
        Long id = getId();
        return id == 0 ? super.hashCode() : id.intValue();
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "-" + getId();
    }
}

当我在某些情况下查询BlogPost时,最奇怪的事情发生了。例如,如果我单独运行下面的查询,那么它可以正常工作,但如果我在一堆其他查询中运行它,那么我会得到下面的异常:

select b from BlogPost b

java.lang.NullPointerException
   at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:240)
   at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1153)
   at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1208)
   at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
   at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)

现在最重要的是,如果我从上面列出的所有映射超类中获取所有字段,并将它们直接放入BlogPost中,使BlogPost不扩展任何内容并实现java.io.Serializable,那么一切都可以完美运行。这让我相信这个错误要么与映射超类有关,要么与我应用于Community ityModelObject的Hibernate过滤器有关。

有没有办法解决这个问题?我假设这是Hibernate中新引入的一个bug,但我可能错了。这给我们带来了重大问题,因为我们需要尽快升级Hibernate Search,这是我们需要进行的关键bug修复。

还要注意,我们使用的数据库是MySQL,带有以下自定义方言,这是我在进行此升级以处理我们的位列时编写的:

public class MySQL5InnoDBDialectExt extends MySQL5InnoDBDialect {

    private static final String BIT_STRING = "bit";

    public MySQL5InnoDBDialectExt() {
        super();
        registerColumnType(Types.BOOLEAN, BIT_STRING);
    }
}

谢谢Brent

共有2个答案

尉迟宣
2023-03-14

希望这对某人有帮助,但在我的情况下,这是一个错误的仪器问题。

我有“A”班和两个孩子“B”班和“C”班类有一个lazy属性,并对其进行检测以使lazy访问工作。

但错误在于我没有对子类“B”和“C”进行插装,因此从“B”和“C”对插装属性的任何访问都会导致异常。

当我插入“B”和“C”时,问题消失了。

解晟睿
2023-03-14

我整理了这个问题,偶然发现了这个问题。这是我在Hibernate论坛上发布的解决方案:

我发现了问题。它似乎与拦截器无关,而是与缓存或插装相关。基本上,我们的应用程序在缓存方案中自动包含一个非常特定的包中的所有实体,并在我们的工具中包含相同的类。我们通常将所有实体都包含在该包中,但导致问题的实体是唯一未包含在该包中的实体。我们使用的早期版本的EhCache/Hibernate对此似乎没有问题,但升级后会出现问题。

无论如何,实体在错误的包中,当我重构它并将其移动到正确的包中时,一切都正常了!因此,这不是Hibernate中的一个bug,只是一个信息丰富的异常,使得很难跟踪这个问题(我基本上是侥幸解决的)。

 类似资料:
  • 我们目前正在使用搜索踢宝石,它的工作原理很棒。最近我尝试在本地开发环境中将elasticsearch升级到7。我得到了它,并使用家庭酿造运行(研究后,我需要运行)。当我去重新索引我的模型之一时,我得到了以下映射错误: 使用elasticsearch 6.8.4时不会出现此错误。有人能给我指一个解决这个问题的资源吗?

  • Flask 如同其它软件一样,会随着时间不停地更新自己,其中大部分都会是非常体贴的, 你无需改动一行自身代码就可以应用新版本的 Flask。 不过,每当 Flask 有更新时,我们都建议你适当地修改自己的代码,以充分地利用这些新功能, 提高自己代码地质量。 本章节文档为您列举了 Flask 各版本之间地差异,以及你如何修改自身代码才能无痛地升级。 如果你使用 easy_install 命令更新、安

  • 介绍云联壹云产品如何进行升级操作。 从3.6升级到3.7 介绍云联壹云产品如何进行升级操作。 从v2.13升级至v3.2 介绍云联壹云产品如何进行升级操作。

  • 我正在做一个简单的部分更新场景,它适用于Solr的6.x和7.x版本。将Solr和Solrj升级到8.8后,我遇到以下异常: 注意,这与前面关于stackoverflow的问题不同,因为我传递的是简单的整数字段,而在Solr/Lucene端,它被替换。

  • 我在Ubuntu18.04上使用ELasticsearch。当我尝试运行“./elasticsearch-setup-passwords”脚本时,它显示以下错误。 未来版本的Elasticsearch将需要Java 11;您的Java版本[/usr/lib/jvm/java-8-openjdk-amd64/jre]不符合此要求 但当我检查Jaa版本时,它显示的是Java 11号。 我把Java从8