当前位置: 首页 > 面试题库 >

休眠单向关联的麻烦

贲绪
2023-03-14
问题内容

我正在尝试在Java应用程序中实现Hibernate持久层,但遇到了一些麻烦。每次尝试访问简单的单向关联时,我都会遇到无代理错误。我没有以正确的方式实现Hibernate-
我正在使用会话控制的线程方法,他们确实建议您不要将其用于生产。但是,他们在教程中使用它。我仍在尝试使基础知识正常运行,因此我认为按照教程进行操作是可以的。但是,我无法使用简单的关联来工作。我有一堂课,看起来像这样:

public class Foo {
    private Long id;
    private String name;
    private Bar bar;

    // Static Handler Methods - I'll flesh these out further down in the question.
    public static List getAllFoo();


    // Convenience methods
    public String getBarName() {
        return bar.getName();
    }

    // Accessor methods
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Bar getBar() {
        return bar;
    }

    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

Foo的Bar类实现为简单的单向关联。像这样在.hbm.xml中:

<many-to-one name="bar" column="bar_id" not-null="true" />

我在Foo内部的静态方法中创建Foo,如下所示:

public static List getAllFoo() {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction t = session.beginTransaction();
    List foos = session.createCriteria(Foo.class).list();
    t.commit();
    return foos;
}

hibernate实例配置为使用1的连接池,并使用线程方法进行会话处理,如下所示:

<property name="connection.pool_size">1</property>
<property name="current_session_context_class">thread</property>

每次尝试使用getBarName()创建的对象之一上的函数访问关联时,都会遇到异常。这是一个代理错误,看起来像这样:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at Bar_$$_javassist_7.getName(Bar_$$_javassist_7.java)
    at Foo.getBarName(Bar.java:126)

简而言之,这就是我刚开始时遇到的错误。从那以后,我花了几天的时间阅读Hibernate文档和此处的文章,以尝试弄清楚如何进行这项工作。

我了解到-我认为-
Hibernate对象需要连接到Session。即,它们创建的会话。当我创建对象时getAllFoo(),就是那些对象所涉及的会话。在该会话中,律师代理存在并且有意义。但是,当我打电话时t.commit()-因为我使用的是Session处理的Thread方法-
我要结束该Session。其结果是,当我以后去打电话时bar.getName(),bar现在是一个孤立的代理。这是一个代理,其会话已关闭。

我发现了两种可能的解决方案:

1)不要关闭初始会话。通过不打电话t.commit()来使其保持打开状态getAllFoo()

这行得通-但是,我认为我无法使用它。我将一次加载数千个这些对象。他们将需要长时间保持开放,而用户需要思考的时间-
但是我需要能够自由访问关联。将来,数据库锁可能会出现并发问题。

2)在调用关联之前,将对象重新附加到新的Session。

这没用。也许我做错了-我发现的文档不清楚。我尝试开始一个新的会话并session.load(this, this.id)在访问该关联之前进行呼叫。像这样:

public Bar getBar() {
    Bar tmp = null;
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction t = session.beginTransaction();
    session.load(this, this.id);
    tmp = bar;
    t.commit();
    return tmp;
}

然后getBarName(),我修改为调用getBar()而不是访问bar。这导致了一个新的错误:

org.hibernate.PersistentObjectException: attempted to load into an instance that was already associated with the session: [Foo#1]

我想即使在阅读了几天的教程,帖子和hibernate文档之后,我仍然无法绕过这种结构。因此,我要求StackOverflow对此进行一些说明。

首先,如果您能弄清楚,我目前拥有的代码中发生了什么?
会话是打开还是关闭?为什么在第一种方法中出现代理错误,但是在第二种方法中却声称会话仍被打开并且对象仍处于连接状态?

其次,处理会话的正确方法是什么-我该如何实际工作? 我认为我要使用的方式是每个请求会话-
这似乎是最受欢迎的,并且适用于我的情况。但是,该如何在关联和延迟加载中实现呢?

是的,我知道我不应该使用线程方法-但是我还有其他一系列与JTA,线程与托管相关的问题,这个问题已经太长了。


问题答案:

我相信Hibernate默认为延迟初始化。因此,当您在会话中加载Foos列表时,在尝试使用它们之前,不会加载任何与它们关联的Bar。到那时,您已经关闭了会话,从而导致错误。

一些潜在的解决方案:

  • 启用对Foo-Bar关联的热切获取
  • 在获取时“加入”(实际上是急切的获取)
  • 尝试在会话中访问Bar(这将起作用,但是您正在调用Foo.getBar()只是为了加载关联的Bar对象)

评论更新:

用于会话/事务管理的惯用语:

Session sess = factory.openSession();
Transaction tx;
  try {
    tx = sess.beginTransaction();
    //do some work
    ...
    tx.commit();
  }
  catch (Exception e) {
    if (tx!=null) tx.rollback();
      throw e;
  }
  finally {
    sess.close();
  }

重新附加“分离的”对象(基于参考文档):

如果对象已被修改:在新会话中更新对象

// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);

// in a higher layer of the application
cat.setMate(potentialMate);

// later, in a new session
secondSession.update(cat);  // update cat
secondSession.update(mate); // update mate

如果对象未修改,则可以使用lock():

//just reassociate:
sess.lock(fritz, LockMode.NONE);
//do a version check, then reassociate:
sess.lock(izi, LockMode.READ);
//do a version check, using SELECT ... FOR UPDATE, then reassociate:
sess.lock(pk, LockMode.UPGRADE);


 类似资料:
  • 问题内容: 我有两个与多对多关联的表。 —数据库片段: 加载 ID 名称 会话 ID 日期 sessionsloads LoadId 的SessionID —hibernate映射片段: 为了从关联表 sessionloads中 删除一个条目,我执行以下代码: 但是,启动后,此代码将保持不变。 删除关联的正确方法是什么? 问题答案: 您需要更新和之间的链接的两端: 实际上,许多开发人员使用防御性方

  • 问题内容: 我希望UserAcounts可以有许多UserGroups,而所有Groups可以有许多Users。还有一个联接表。我希望在删除useraccount时删除联接表中useraccount和usergroup之间的关系。 实际上,我想使用“在删除级联上”。在ManyToMany关系中,我不会不幸地运行它。我已经尝试了很多事情,但没有找到解决方案。 注意:我只想在删除级联上删除关系 是否有

  • 问题内容: 我有一个关于Hibernate的一般性问题,我正在与之讨论。 我有A类和B类,其中B依赖于A 在我的代码中,当我调用em.persist(objOfTypeA)时,我希望插入内容能够插入到表AAA和BBB中。如果我手动使用A获取A的ID并将其填写在每个对象的列表中,然后保留该列表,则说明一切正常。但是我希望Hibernate 能够 神奇地 做到这一点。 难道我做错了什么?还是我只是对H

  • 问题内容: 我这样做是为了对实体对象进行延迟加载: 我想与多个延迟加载的集合返回一个实体对象 加载的 ,我能做到这一点(通过在列表中,并设置超过联想单个标准是什么?): 问题答案: 是? 该文档包含以下内容: 该查询将通过外部联接获取伴侣和小猫。有关更多信息,请参见第20.1节“获取策略”。

  • 问题内容: 有一个“ Item”类,它有一些相关的类,称为Vehicle,Vmodel,Category,ItemName,Brand,SizeModel。每个类都有属性ID和名称(例如Vehicle类,“ vid”和“ vname”)。 Item类具有itemcode。 另外,我还需要从给定的示例Item对象(称为“ ”)中获取Item对象,该对象等于我的示例item对象的属性以及与该对象关联的

  • 问题内容: 关于以下与Hibernate有关的问题,我几乎看不到任何指针。这涉及到使用具有自身父子关系的单个数据库表来实现继承。例如: 在这里, managerId 列可以为null,或者可以指向 Employee 表的另一行。业务规则要求员工了解他的所有报告人以及他/她的经理。业务规则还允许行具有为空的 managerId (组织的CEO没有经理)。 我们如何在Hibernate中映射此关系,标