简体   繁体   English

JPA 2.0 / Hibernate:为什么LAZY使用“@OneToOne”开箱即用?

[英]JPA 2.0 / Hibernate: Why does LAZY fetching with “@OneToOne” work out of the box?

my question is regarding JPA 2.0 with Hibernate, @OneToOne relationships and lazy loading. 我的问题是关于JPA 2.0与Hibernate,@ OneToOne关系和延迟加载。

First my setup: 首先我的设置:

  • Spring 3.0.5.RELEASE Spring 3.0.5.RELEASE
  • SprnigData JPA 1.0.1.RELEASE SprnigData JPA 1.0.1.RELEASE
  • Hibernate 3.5.2-Final Hibernate 3.5.2-最终版
  • DBMS: PostgreSQL 9.0 DBMS:PostgreSQL 9.0

I recently came across the fact, that a @OneToOne relationship can't be fetched the lazy way (FetchType.LAZY), at least not without byte code instrumentation, compile time weaving or the like. 我最近发现这样一个事实:@OneToOne关系不能以懒惰的方式(FetchType.LAZY)获取,至少没有字节代码检测,编译时间编织等。 Many sites out there say this, for example: 许多网站都说这个,例如:

The thing is, with my setup, a lazy loading of a @OneToOne entity seems to work "out of the box", and I really would like to understand why. 事情是,在我的设置中,@OneToOne实体的延迟加载似乎“开箱即用”,我真的想了解原因。 Please, have a look at my unit test: 请看看我的单元测试:

@Test
@Transactional
public void testAvatarImageLazyFetching()
{
    User user = new User();
    user.setAvatarImage( new AvatarImage() );

    User = userRepository.save( user );

    entityManager.flush();
    entityManager.clear();

    User loadedUser = userRepository.findOne( user.getId() );
    assertNotNull( loadedUser );

    PersistenceUtil persistenceUtil = Persistence.getPersistenceUtil();

    assertTrue( persistenceUtil.isLoaded( loadedUser ) );
    assertFalse( persistenceUtil.isLoaded( loadedUser, "avatarImage" ) );
}

This test case is successful, and in Hibernates SQL logging output, I can see clearly, that the "avatarImage" will not be fetched, just the "user" (just a single SELECT, no JOIN, no access to the "AvatarImage" table etc.) 这个测试用例是成功的,在Hibernates SQL日志输出中,我可以清楚地看到,“avatarImage”不会被提取,只是“用户”(只有一个SELECT,没有JOIN,没有访问“AvatarImage”表)等等。)

The unidirectional @OneToOne relationshop in the User class looks like this: User类中的单向@OneToOne关系服务如下所示:

@OneToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
private AvatarImage    avatarImage;

So, everything very simple - and it seems to work. 所以,一切都很简单 - 它似乎工作。

To repeat my question: why is it working, why can the "AvatarImage" be fetched lazily, although it is referenced with a @OneToOne association? 重复我的问题:为什么它可以工作,为什么可以懒惰地取出“AvatarImage”,尽管它是用@OneToOne关联引用的?

I really appreciate any help you can offer 我非常感谢您提供的任何帮助

Thanks a lot! 非常感谢!

The problem with lazy loading of OneToOne relationship is only on the inverse part of it (the one which is marked with mappedBy attribute). 延迟加载OneToOne关系的问题仅在于它的反向部分(用mappedBy属性标记的那个)。 It works fine on the owning side of the relationship. 它在关系的拥有方面运作良好。 T he difference between those is clear on database level. 这些之间的差异在数据库级别上是明确的。 In your case the question is if the User database table holds an id of AvatarImage as one of the columns or the other way round. 在您的情况下,问题是用户数据库表是否将ID为AvatarImage作为其中一列或反之。 If User table has a column with an id of AvatarImage then the lazy loading will work as you said "out-of-box" but it will not work the other way round. 如果User表有一个id为AvatarImage的列,那么延迟加载将像你说的“开箱即用”一样工作,但它不会反过来工作。

Lazy fetching works out of the box for @OneToOne annotated relationships, with the Hibernate JPA provider, when some form of bytecode instrumentation is performed. 当执行某种形式的字节码检测时,使用Hibernate JPA提供程序进行@OneToOne注释关系的延迟提取工作开箱即用。 In your case, we could rule out build-time instrumentation (inferring from your comment that it works out-of-the-box). 在您的情况下,我们可以排除构建时间工具(从您的评论中推断出它是开箱即用的)。 This leaves you with the possibility of runtime weaving, which is quite possible in Hibernate & Spring. 这使您有可能进行运行时编织,这在Hibernate和Spring中是很有可能的。 In recent releases of Hibernate, Javassist is used as the runtime bytecode instrumentation framework for Hibernate, as opposed to the other alternative of CGLIB ( which has been deprecated since Hibernate 3.5.5 ). 在最近的Hibernate版本中,Javassist被用作Hibernate的运行时字节码检测框架,而不是CGLIB的另一种选择( 自Hibernate 3.5.5以来已被弃用 )。

The question of whether Javassist is enabled in Spring is quite simple to answer. 在Spring中是否启用Javassist的问题很容易回答。 Hibernate EntityManager (which is the JPA 2.0 provider that delegates to Hibernate Core), requires Javassist, and therefore, it ought to be in the classpath of Hibernate, allowing for runtime weaving of the classes. Hibernate EntityManager(委托给Hibernate Core的JPA 2.0提供者)需要Javassist,因此它应该在Hibernate的类路径中,允许运行时编织类。 You can confirm this by setting a breakpoint (in a remote debugger connected to your application server), and you'll notice that a Hibernate managed instance of the User class will not contain a reference to an AvatarImage instance; 您可以通过设置断点(在连接到应用程序服务器的远程调试器中)来确认这一点,并且您会注意到User类的Hibernate托管实例不包含对AvatarImage实例的引用; rather it would contain a reference to an enhanced class with a name like <package_name>.AvatarImage_$$_javassist_0 (which is the proxy that allows for lazy fetching). 相反,它将包含对名为<package_name>.AvatarImage_$$_javassist_0 (允许延迟提取的代理)的增强类的引用。

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

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