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

JPA和Hibernate代理行为

呼延骏俊
2023-03-14

我试图观察下面的JPA2/Hibernate4代理行为,

//延迟加载的循环实体:

@Entity
public class Employee {

 @Id@Generated
 int id;
 String name;
 @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
 Employee boss;

 public String toString() {
  return id + "|" + name + "|" + boss;
 }

 //getters and setters ...

}

//持久实体:

// Outer entity:
Employee employee = new Employee();
employee.setName("engineer");
// Inner entity:
Employee boss = new Employee();
boss.setName("manager");
employee.setBoss(boss);

entityTransaction.begin();
entityManager.persist(employee);
entityTransaction.commit();
System.out.println(employee);

//输出:

Hibernate: insert into Employee (id, boss_id, name) values (default, ?, ?)
Hibernate: insert into Employee (id, boss_id, name) values (default, ?, ?)

2|engineer|1|manager|null

//加载外部实体:

String queryString = "select e from Employee e where e.id=" + employee.getId();
Query query = entityManager.createQuery(queryString);
Object loadedEmployee = query.getSingleResult();
System.out.println(loadedEmployee.getClass().getSimpleName());

//输出:

Hibernate: select employee0_.id as id2_, employee0_.boss_id as boss3_2_, employee0_.name as name2_ from Employee employee0_ where employee0_.id=2 limit ?

Employee

令我惊讶的是,上面加载的外部实体仍然是普通实体,但我希望它是Hibernate代理,这是由于延迟加载造成的。我可能错过了一些东西,那怎么做才对呢?一个简单而具体的例子是非常感谢!

@编辑

根据@kostja的回答,我修改了代码,并在下面的SE模式下对其进行了调试,既不能生成LazyInitializationException,也不能代理boss属性。有进一步的提示吗?

@编辑2

最后,我要确认来自@kostja的答案无疑是非常棒的。

我在EE模式下进行了测试,因此下面观察到了代理boss属性

//LazyInitializationException引发:

public Employee retrieve(int id) {
 Employee employee = entityManager.find(Employee.class, id);
 // access to the proxied boss property outside of persistence/transaction ctx
 Employee boss = employee.getBoss();
 System.out.println(boss instanceof HibernateProxy);
 System.out.println(boss.getClass().getSimpleName());
 return boss;
}

//将Spring Tx放置到位后,绿灯亮起:

@Transactional
public Employee retrieve(int id) ...

//输出:

true
Employee_$$_javassist_0

此外,可以参考20.1.4。从Hibernate文档初始化集合和代理。


共有1个答案

公羊兴文
2023-03-14

这是预期的JPA行为。没有理由代理查询中的实体——它是查询的常规结果。但是,此实体的boss属性应该是代理。不过,如果被询问,它不会告诉您——当您对托管实体的延迟加载属性执行任何操作时,它将触发获取。

因此,您应该在事务之外访问boss属性。如果尚未提取,您将得到一个LazyInitializationException

您将如何处理它取决于EntityManagerPersistenceContext的类型。

  • 仅在JPA 2.0之后有效-调用em.detach(loadedEmployee)然后访问boss属性

对于JPA 1:

>

在具有用户事务的SE环境中,在访问boss属性之前调用transaction.commit()

如果使用将延长事务寿命的EXTENDEDPeristenceContext,请调用em.clear()

艾德:我想你没有得到异常的原因是FetchType。LAZY只是对JPA提供者的一个提示,因此不能保证该属性被延迟加载。与此相反,FetchType。急切的保证了急切的抓取。我想,你的JPA提供商选择了急切地加载。

我复制了这个例子,不过有点不同,我在log语句中重复得到了LazyInitializationException。该测试是在JBoss 7.1.1上运行的Arquillian测试,JPA 2.0在Hibernate 4.0.1上运行:

@RunWith(Arquillian.class)
public class CircularEmployeeTest {
    @Deployment
    public static Archive<?> createTestArchive() {
        return ShrinkWrap
                .create(WebArchive.class, "test.war")
                .addClasses(Employee.class, Resources.class)
                .addAsResource("META-INF/persistence.xml",
                        "META-INF/persistence.xml")
                .addAsResource("testSeeds/2CircularEmployees.sql", "import.sql")
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @PersistenceContext
    EntityManager em;

    @Inject
    UserTransaction tx;

    @Inject
    Logger log;

    @Test
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void testConfirmLazyLoading() throws Exception {
        String query = "SELECT e FROM Employee e WHERE e.id = 1";

        tx.begin();
        Employee employee = em.createQuery(query,
                Employee.class).getSingleResult();
        tx.commit();
        log.info("retrieving the boss: {}", employee.getBoss());
    }
}
 类似资料:
  • 问题内容: 我有一个抽象ID和版本属性的BaseEntity。此类还实现哈希码,并基于PK(id)属性进行等于。 现在两个实体A和B扩展了BaseEntity,如下所示 关闭会话以懒惰的b加载a并尝试a1.getB()。equals(b1)给出false,但如果我与a1.getB()。getId()。equals(b1.getId())比较,则得出真正的奇怪!我认为是因为Java辅助代理对象,无论

  • 我试着调整我的应用程序,所以我把关系变成懒惰的,只取我需要的东西 我的多对一关系有一个问题,当我再次加载实体时转到lazy时,Hibernate将实体替换为代理,即使我获取了该实体,而该代理在应用程序的视图部分(JSF)中不工作。当多对一处于急切模式时,问题就会消失,但hibernate会为每个多对一执行一个select more(选择更多),即使我不需要它们 1/ 2/ JPQL查询: =>两次

  • 我正在使用Adobe Experience Manager(AEM)6.4和Service Pack 1以及表单包。我有很多扩展属性,所以我做了一个数据库图。我不想在crx中保存所有其他内容,我想将其保存在Oracle数据库中。 数据库图很复杂,所以我想至少使用JPA(Hibernate)。如果Spring能让它更容易使用,那对我来说就没问题了。 我读了很多关于OSGI使用蓝图而不是Spring的

  • Spring Data JPA不是一个JPA实现,它是对数据库数据访问的抽象。我不能理解这种表达方式与JPA的实现(比如Hibernate)进行比较。在使用Spring Data JPA时,要使用CRUD操作,必须从CrudRepository接口进行扩展。但是没有Hibernate,Spring Data JPA无法独立工作,因为它无法将java对象转换为实体。但是!Hibernate还可以执行

  • 问题内容: 我正在尝试在我的工作原型中实现EHCache,在该原型中我有一个 javax.persistence.Entity,它 表示数据库中的表(MySQL,mysql-connector-java-5.1.20.jar),该XML作为XML提供给消费者。 我面临的问题是, 即使EHCache将查询结果存储在memory上 ,Hibernate似乎仍从数据库中检索数据。 我正在使用EHCach

  • 我面临的问题是,Hibernate似乎仍然从数据库中检索数据,即使EHCache将查询结果存储在内存中。 我使用EHCache监视器来查看内存中项的计数,并在缓存过期之前直接更改数据库中的数据,以了解缓存的数据是否被实际使用。 我一直在为这个问题寻找一个复制,但没有成功,所以可能我错过了什么(我只是进入了java世界)。 *我试着设置eternal=“true”,但结果还是一样 persisten