远程处理案例中的懒惰/急切加载策略 (JPA) [英] Lazy/Eager loading strategies in remoting cases (JPA)

查看:17
本文介绍了远程处理案例中的懒惰/急切加载策略 (JPA)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了 LazyLoading 异常,就像大多数尝试使用 ORM 进行远程处理的人一样.在大多数情况下,切换到预先获取可以解决问题(延迟加载/非原子查询/线程安全/n+1 问题......).但是,如果您正在处理一个非常大的对象图,急切获取也有缺点.

I'm running into LazyLoading exceptions like the most people who try remoting with an ORM. In most cases switching to eager fetching solves the problem (Lazy Loading / Non atomic queries / Thread safety / n+1 problem ...). But eager fetching has also disadvantages if you are dealing with a really big object graph.

在大多数用例中不需要加载整个对象图.加载更多然后需要的数据(或从数据库加载它们并提取所需的子集)感觉很糟糕.

Loading the whole object graph isn't needed in the most use-cases. It feels bad to load more data then needed (or load them from the db and extract the needed subset).

那么有哪些替代方法可以解决此类问题(在运行时)?
我见过:

So what alternative ways are there to solve this kind of problem (at runtime)?
I've seen:

  • 将数据访问依赖项注入到域对象中,并让对象决定是加载懒惰还是急切:感觉不好!领域层应该独立于任何服务.域注入也是一项昂贵的操作.域应该是数据访问无知的,并且应该在有或没有数据访问的情况下使用.
  • 除了需要更多数据的用例外,懒惰地获取所有内容:似乎性能更好,但这种方式会强制执行许多客户端=>服务器/数据库往返.惰性字段的初始化也可能会很痛苦(用 JPA 尝试过).这种方式感觉不通用并且受到上述相同的惰性限制.
  • 在 Lazy 类中封装持久性:更复杂,没有与 ORM 互操作的最佳实践.膨胀的服务层(这么多手写"代码感觉不好).
  • 对每个用例使用完整的预测:我们最终会使用 SQL 并放弃 ORM 的好处.
  • DTO/虚拟代理层会强制执行更多复杂性并使代码更难维护(虫洞反模式 >> 膨胀).
  • Inject a data access dependency into domain object and let the object decide either to load lazy or eager: Feels bad! The domain layer should be independent from any service. Domain injection is also an expensive operation. The domain should be data access ignorant and should be used with or without data access.
  • Fetch everything lazy except of use-cases which require more data: Seems better for performance but this way forces many client=>server / database roundtrips. The initialisation of the lazy fields can also suffer pain (tried with JPA). This way doesn't feel generic and is subject of the same lazy restrictions mentioned above.
  • Encapsulate persistence in Lazy class: More complexity, no best practice for interoperation with ORM. Bloating services layer (so much "hand written" code feels bad).
  • Use full projections for every use-case: We'll end up in SQL and drop the benefit of an ORM.
  • A DTO / Virtual Proxy layer enforces more complexity and makes code harder to maintain (Wormhole antipattern >> Bloat).

我想了很多另一种方式.也许通用投影白/黑名单是一个解决方案.

I thought a lot about another way. Maybe generic projection white./black listning is a solution.

想法(黑名单):定义一个类名列表,其中包含获取操作的边界.如果属性匹配并且它是惰性的,则删除惰性 (CGLIB) 代理并用 null 填充该值.否则,简单地防止获取(并将值保留为空).所以我们可以在我们的 DAO 中设置明确的界限.

Idea (blacklist): Define an classname list with the boundaries for a fetching operation. If a property matches and it's lazy, remove the lazy (CGLIB) proxy and fill the value with null. Else, simple prevent from fetching (and leave value at null). So we can set clear boundaries in our DAOs.

示例:ProductDao.findByName("Soap",Boundaries.BLACKLIST,"Category, Discount")最后两个参数也可以绑定到一个 Boundaries 对象中.

Example: ProductDao.findByName("Soap",Boundaries.BLACKLIST,"Category, Discount") the two last parameters can also been bound into a Boundaries object.

idea(白名单):类似于黑名单,但是你必须声明属性应该加载到白名单中.

Idea (whitelist): Like blacklist, but you must declare properties with should be loaded in a whitelist.

您如何看待这样的解决方案?(可能的问题、限制、优势……)我应该如何用java写这个?也许通过 AOP 来匹配 DAO 方法(因为我可以在那里修改 cglib 代理行为)?

What do you think about such a solution? (Possible problems, restrictions, advantages ...) How should I write this in java? Maybe via AOP to match DAO methods (because I'm able to modifiy cglib proxy behaviour there)?

推荐答案

  1. 您可以删除所有集合并使用 NamedQueries 代替.我们在一个项目(EJB + Swing)中使用了这种方法,并且效果很好——因此您可以确定要获取的确切数据.NamedQueries 是普通查询,将它们想象成 PreparedStatement-s.这个想法不是通过查询创建/检索/更新/删除单个对象.这个想法是您通过查询获取Collections.例如,不是映射@ManyToMany 列表,而是定义一个获取该列表的 NamedQuery.因此,您可以单独获取集合数据,并且仅在需要时才获取,而不是自动获取.

  1. You can get rid of all collections whatsoever and use NamedQueries instead. We used this approach in one project (EJB + Swing), and it worked pretty well - thus you determine exact data to be fetched. NamedQueries are normal queries, imagine them as PreparedStatement-s. The idea is not to create/retreive/update/delete single objects with queries. The idea is that you fetch your Collections with queries. For example, instead of mapping a @ManyToMany List, define a NamedQuery that fetches that list. Thus you can fetch the collection data separately, and only whenever you need it, not automatically.

为传输的对象使用自定义代理(使用 CGLIB) - 每当引用集合(通过其 getter)时,尝试重新获取,并捕获任何 LazyInitializationException 并调用服务器请求数据的层.

Use a custom Proxy (using CGLIB) for transferred objects - whenever a collection is referenced (via its getter), attempt retreival, and catch any LazyInitializationException and make a call to the server tier for the data requested.

和上一个一样,但是只代理集合,就像 Hibernate 在需要延迟初始化时代理它们一样.

Just as the previous one, but make proxies only of the collections, in the way Hibernate proxies them when lazy initialization is needed.

另外,看看值列表处理程序 模式 - 可能有用.

Also, take a look at the Value List Handler pattern - might be useful.

(你也可以使用hibernate.max_fetch_depth(如果使用 Hibernate)与上述组合,如果它适合您的情况.)

(You can also use hibernate.max_fetch_depth (if using Hibernate) with a combination of the above, if it is suitable for your case.)

这篇关于远程处理案例中的懒惰/急切加载策略 (JPA)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆