繁体   English   中英

在DAO方法中访问延迟加载的集合时发生NullPointerException

[英]NullPointerException when accessing lazy loaded collection within DAO method

在应用程序中运行多个线程时,Spring和Hibernate出现了一个奇怪的问题。 我正在使用spring 3.2.0.RELEASE和hibernate 4.1.12.Final。 问题在于,对于某些对象,当从数据库中检索到它们时,检索成功,但是未设置所有映射的集合。 这是我的回购示例:

@Repository("fooRepository")
public class FooRepository {

    private static final Logger log = Logger.getLogger(FooRepository.class);

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    @Transactional
    public Foo retrieve(final Long id) {
        Foo instance = (Foo) sessionFactory.getCurrentSession().get(Foo.class, id);
        for (CollectionMember member : instance.getCollectionMembers()) {
            log.debug(member.getId());      
        }
        return instance;
    }

对于某些对象,在尝试访问CollectionMember列表时,此方法始终会引发以下错误:

Caused by: java.lang.NullPointerException
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:501)

问题在于,session.get()调用会为所有延迟加载的集合创建PersistentBag对象,但从不设置内容。 仅在启用多线程时才会发生这种情况。 谁能解释为什么会这样?

编辑:这是foo类的相关位:

@Entity
@Table(name = "FOO")
@XmlRootElement(name = "foo")
public class Foo {

    @EmbeddedId
    private FooPK id;

    @OneToMany
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumns({
            @JoinColumn(name = "COLLECTION_ID", referencedColumnName = "COLLECTION_ID"),
            @JoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID")})
    private List<CollectionMember> collectionMembers = new ArrayList<CollectionMember>();

还有CollectionMember类:

@Entity
@Table(name = "COLLECTION_MEMBER")
@XmlRootElement(name = "collectionMember")
public class CollectionMember {

    @EmbeddedId
    private CollectionMemberPK primaryKey;

    @ManyToOne
    @JoinColumn(name = "COLL_CODE")
    private CollectionCode collectionCode;

问题是@NotFound(action = NotFoundAction.IGNORE)

如果找不到集合记录,这将创建一个返回的对象null而不是一个空集合。 删除并测试

我认为您应该使用第三个联接表,并使用Criteria加载集合。

    @OneToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "table", joinColumns = {@JoinColumn(name = "COLLECTION_ID", nullable = false)}, inverseJoinColumns = { @JoinColumn(name = "FOO_ID", nullable = true) })
    private List<CollectionMember> collectionMembers = new ArrayList<CollectionMember>();


@ManyToOne(mappedBy="collectionMembers")
private CollectionCode collectionCode;

多线程在哪里发挥作用? 如何确保单个线程始终使用相同的休眠会话?

当您遍历集合Hibernate时,我了解休眠和延迟加载的方式将在CurrentSession中查找。 在多线程环境中,该会话可能已经被另一个线程使用。 我不确定@Transactional是否足以保留您相同的Hibernate会话。

为此可能会有一个Hibernate配置。

尝试以下方法。

Foo instance = (Foo) sessionFactory.getCurrentSession().get(Foo.class, id);

Hibernate.initialize(instance.getCollectionMembers())

for (CollectionMember member : instance.getCollectionMembers()) {

        log.debug(member.getId());      
}

return instance;

除非另有说明,否则默认情况下,Hibernate会将所有* ToMany集合映射标记为惰性。 一个线程无法加载对象,并且无法在一个@Transactional方法中读取关联的惰性集合。

在您的情况下,什么是多线程? 您是手动生成线程还是Web应用程序? 您如何设置会话范围?

顺便说一句,如果您真的想解决问题,我建议您发布stacktrace ..可能需要花费几秒钟的时间来替换您的商业软件包名称,以防万一。

在春季环境中使用休眠模式时,建议不要直接通过会话工厂获取会话,否则可能导致会话泄漏。 尝试用以下模式替换:

getHibernateTemplate().execute(new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException, SQLException {
            Foo instance = (Foo) session.get(Foo.class, id);
            //whatever logic goes here
            return instance;
        }
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM