JPA 2.0 / Hibernate:为什么使用“@OneToOne”进行 LAZY 获取?开箱即用?
我的问题是关于 JPA 2.0 与 Hibernate、@OneToOne 关系和延迟加载。
首先是我的设置:
- Spring 3.0.5.RELEASE
- SprnigData JPA 1.0.1.RELEASE
- Hibernate 3.5.2-Final
- DBMS:PostgreSQL 9.0
我最近发现一个事实,@OneToOne 关系不能以惰性方式获取(FetchType. LAZY),至少没有字节码检测、编译时编织等。许多网站都这么说,例如:
- http://community.jboss.org/ wiki/SomeExplanationsOnLazyLoading 一对一
- http://justonjava.blogspot。 com/2010/09/lazy-one-to-one-and-one-to-many.html
- 使 OneToOne 关系变得懒惰
问题是,通过我的设置,@ 的延迟加载OneToOne 实体似乎“开箱即用”,我真的很想了解为什么。请看一下我的单元测试:
@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" ) );
}
这个测试用例是成功的,在 Hibernates SQL 日志输出中,我可以清楚地看到,“avatarImage”不会被获取,只有“user”(只是一个 SELECT,没有JOIN,无法访问“AvatarImage”表等。)
User 类中的单向 @OneToOne 关系如下所示:
@OneToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
private AvatarImage avatarImage;
所以,一切都非常简单 - 而且似乎有效。
重复我的问题:为什么它有效,为什么可以延迟获取“AvatarImage”,尽管它是通过 @OneToOne 关联引用的?
我真的很感谢您能提供的任何帮助,
非常感谢!
my question is regarding JPA 2.0 with Hibernate, @OneToOne relationships and lazy loading.
First my setup:
- Spring 3.0.5.RELEASE
- SprnigData JPA 1.0.1.RELEASE
- Hibernate 3.5.2-Final
- 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. Many sites out there say this, for example:
- http://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one
- http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html
- Making a OneToOne-relation lazy
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. 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.)
The unidirectional @OneToOne relationshop in the User class looks like this:
@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?
I really appreciate any help you can offer
Thanks a lot!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
OneToOne 关系的延迟加载问题仅出现在其相反的部分(用mappedBy 属性标记的部分)。它在关系的拥有方方面运作良好。时间
它们之间的区别在数据库级别上很明显。在您的情况下,问题是 User 数据库表是否将 AvatarImage 的 id 作为列之一保存,或者反之亦然。
如果 User 表有一列 id 为 AvatarImage,那么延迟加载将按照您所说的“开箱即用”方式工作,但反之则不然。
The problem with lazy loading of OneToOne relationship is only on the inverse part of it (the one which is marked with mappedBy attribute). 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.
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.
当执行某种形式的字节码检测时,延迟获取可以通过 Hibernate JPA 提供程序立即用于
@OneToOne
带注释的关系。对于您的情况,我们可以排除构建时检测(从您的评论中推断它是开箱即用的)。这使您可以进行运行时编织,这在 Hibernate 和 Java 中是完全可能的。春天。在 Hibernate 的最新版本中,Javassist 被用作 Hibernate 的运行时字节码检测框架,而不是 CGLIB 的其他替代方案(自 Hibernate 3.5.5 起已弃用)。Spring 中是否启用 Javassist 的问题很容易回答。 Hibernate EntityManager(它是委托给 Hibernate Core 的 JPA 2.0 提供程序)需要 Javassist,因此它应该位于 Hibernate 的类路径中,从而允许运行时编织类。您可以通过设置断点(在连接到应用程序服务器的远程调试器中)来确认这一点,并且您会注意到
User
类的 Hibernate 托管实例将不包含对AvatarImage
实例;相反,它会包含对名称类似于.AvatarImage_$$_javassist_0
的增强类的引用(这是允许延迟获取的代理)。Lazy fetching works out of the box for
@OneToOne
annotated relationships, with the Hibernate JPA provider, when some form of bytecode instrumentation is performed. 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. 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).The question of whether Javassist is enabled in Spring is quite simple to answer. 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. 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 anAvatarImage
instance; 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).