java 用更轻的解决方案替换完整的 ORM(JPA/Hibernate):推荐的加载/保存模式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17860161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 17:49:55  来源:igfitidea点击:

Replacing a full ORM (JPA/Hibernate) by a lighter solution : Recommended patterns for load/save?

javasqlrepository-patternmybatisjooq

提问by electrotype

I'm developing a new Java web application and I'm exploring new ways (new for me!) to persist the data. I mostly have experience with JPA & Hibernate but, except for simple cases, I think this kind of full ORM can become quite complex. Plus, I don't like working with them that much. I'm looking for a new solution, probably closer to SQL.

我正在开发一个新的 Java Web 应用程序,我正在探索新的方法(对我来说是新的!)来持久化数据。我主要有 JPA 和 Hibernate 的经验,但是,除了简单的情况,我认为这种完整的 ORM 会变得非常复杂。另外,我不太喜欢和他们一起工作。我正在寻找一个新的解决方案,可能更接近 SQL。

The solutions I'm currently investigating :

我目前正在研究的解决方案:

But there are two use cases I'm worrying about with those solutions, compared to Hibernate. I'd like to know what are the recommended patterns for those use cases.

但是,与 Hibernate 相比,我担心这些解决方案有两个用例。我想知道这些用例的推荐模式是什么。



Use Case 1 - Fetching an entity and accessing some of its associated children and grandchildren entities.

用例 1 - 获取一个实体并访问它的一些关联的子实体和孙实体。

  • Let's say I have a Personentity.
    • This Personhas an associated Addressentity.
      • This Addresshas an associated Cityentity.
        • This Cityentity has a nameproperty.
  • 假设我有一个Person实体。
    • Person有一个关联的Address实体。
      • Address有一个关联的City实体。
        • 这个City实体有一个name属性。

The full path to access the name of the city, starting from the person entity, would be :

访问城市名称的完整路径,从个人实体开始,将是:

person.address.city.name

Now, let's say I load the Person entity from a PersonService, with this method :

现在,假设我PersonService使用以下方法从 a 加载 Person 实体:

public Person findPersonById(long id)
{
    // ...
}

Using Hibernate, the entities associated to the Personcould be lazily loaded, on demand, so it would be possible to access person.address.city.nameand be sure I have access to this property (as long as all the entities in that chain are not nullable).

使用 Hibernate,与 关联的实体Person可以按需延迟加载,因此可以访问person.address.city.name并确保我可以访问此属性(只要该链中的所有实体都不能为空)。

But using anyone of the 3 solutions I'm investigating, it's more complicated. With those solutions, what are the recommended patterns to take care of this use case? Upfront, I see 3 possible patterns:

但是使用我正在研究的 3 种解决方案中的任何一种,它都会更复杂。使用这些解决方案,处理此用例的推荐模式是什么?在前面,我看到了 3 种可能的模式:

  1. All the required associated children and grandchildren entities could be eagerly loaded by the SQL query used.

    But the issue I see with this solution is that there may be some other code that needs to access otherentities/properties paths from the Personentity. For example, maybe some code will need access to person.job.salary.currency. If I want to reuse the findPersonById()method I already have, the SQL query will then need to load more information! Not only the associated address->cityentity but also the associated job->salaryentity.

    Now what if there are 10other places that need to access other information starting from the person entity? Should I always eagerly load allthe potentially required information? Or maybe have 12 different service methods to load a person entity? :

    findPersonById_simple(long id)
    
    findPersonById_withAdressCity(long id)
    
    findPersonById_withJob(long id)
    
    findPersonById_withAdressCityAndJob(long id)
    
    ...
    

    But then everytime I would use a Personentity, I would have to know what has been loaded with it and what hasn't... It could be quite cumbersome, right?

  2. In the getAddress()getter method of the Personentity, could there be a check to see if the address has already been loaded and, if not, lazily load it? It this a frequently used pattern in real life applications?

  3. Are there other patterns that can be used to make sure I can access the entities/properties I need from a loaded Model?

  1. 使用的 SQL 查询可以立即加载所有必需的关联子实体和孙实体。

    但是我在这个解决方案中看到的问题是,可能还有一些其他代码需要从实体访问其他实体/属性路径Person。例如,也许某些代码需要访问person.job.salary.currency. 如果我想重用findPersonById()我已经拥有的方法,那么 SQL 查询将需要加载更多信息!不仅是关联address->city实体,还包括关联job->salary实体。

    现在,如果还有10 个其他地方需要从 person 实体开始访问其他信息呢?我应该总是急切地加载所有可能需要的信息吗?或者可能有 12 种不同的服务方法来加载个人实体?:

    findPersonById_simple(long id)
    
    findPersonById_withAdressCity(long id)
    
    findPersonById_withJob(long id)
    
    findPersonById_withAdressCityAndJob(long id)
    
    ...
    

    但是每次我要使用一个Person实体时,我都必须知道什么已经加载了它,什么没有......这可能很麻烦,对吧?

  2. 在实体的getAddress()getter方法中Person,是否可以检查地址是否已经加载,如果没有,则延迟加载它?这是现实生活应用中经常使用的模式吗?

  3. 是否有其他模式可用于确保我可以从加载的模型中访问我需要的实体/属性?



Use Case 2 - Saving an entity and making sure its associated and modified entities are also saved.

用例 2 - 保存实体并确保其关联和修改的实体也被保存。

I want to be able to save a Personentity using this PersonService's method :

我希望能够Person使用 thisPersonService的方法保存实体:

public void savePerson(Person person)
{
    // ...
}

If I have a Personentity and I change person.address.city.nameto something else, how can I make sure the Cityentity modifications will be persisted when I save the Person? Using Hibernate, it can be easy to cascadethe save operation to the associated entities. What about the solutions I'm investigating?

如果我有一个Person实体并且我更改person.address.city.name为其他实体,我如何确保在City保存Person. 使用 Hibernate,可以很容易地将保存操作级联到关联的实体。我正在研究的解决方案呢?

  1. Should I use some kind of dirtyflag to know what associated entities also have to be saved when I save the person?

  2. Are there any other known patterns useful to deal with this use case?

  1. 我是否应该使用某种标志来了解在我保存此人时还必须保存哪些关联实体?

  2. 是否有任何其他已知模式可用于处理此用例?



Update: There is a discussionabout this question on the JOOQ forum.

更新:有一个讨论有关在JOOQ论坛这个问题。

采纳答案by leonbloy

This kind of problem is typical when not using a real ORM, and there is no silver bullet. A simple design approach that worked for me for a (not very big ) webapp with iBatis (myBatis), is to use two layers for persistence:

这种问题在不使用真正的 ORM 时很典型,没有灵丹妙药。一个对我来说适用于带有 iBatis (myBatis) 的(不是很大的)web 应用程序的简单设计方法是使用两层持久化:

  • A dumb low-level layer: each table has its Java class (POJO or DTO), with fields that maps directly to the table columns. Say we have a PERSONtable with a ADDRESS_IDfield that points to an ADRESStable; then, we'd have a PersonDbclass, with just a addressId(integer) field; we have no personDb.getAdress()method, just the plain personDb.getAdressId(). These Java classes are, then, quite dumb (they don't know about persistence or about related classes). A corresponding PersonDaoclass knows how to load/persist this object. This layer is easy to create and maintain with tools like iBatis + iBator (or MyBatis + MYBatisGenerator).

  • A higher level layer that contains rich domain objects: each of these is typically a graphof the above POJOs. These classes have also the intelligence for loading/saving the graph (perhaps lazily, perhaps with some dirty flags), by calling the respective DAOs. The important thing, however, is that these rich domain objects do not map one-to-one to the POJO objects (or DB tables), but rather with domain use cases. The "size" of each graph is determined (it doesn't grow indefinitely), and is used from the outside like a particular class. So, it's not that you have one rich Personclass (with some indeterminate graph of related objects) that is used is several use cases or service methods; instead, you have several rich classes, PersonWithAddreses, PersonWithAllData... each one wraps a particular well-limited graph, with its own persistence logic. This might seem inefficient or clumsy, and in some context it might be, but it happens often that the use cases when you need to save a full graph of objects are actually limited.

  • Additionally, for things like tabular reports, (specific SELECTS that return a bunch of columns to be displayed) you'd not use the above, but straight and dumb POJO's (perhaps even Maps)

  • 一个愚蠢的低级层:每个表都有它的 Java 类(POJO 或 DTO),具有直接映射到表列的字段。假设我们有一个PERSON带有ADDRESS_ID指向表的字段的ADRESS表;然后,我们会有一个PersonDb类,只有一个addressId(整数)字段;我们没有 personDb.getAdress()方法,只有普通的personDb.getAdressId()。因此,这些 Java 类非常愚蠢(它们不了解持久性或相关类)。相应的PersonDao类知道如何加载/保留此对象。该层易于使用 iBatis + iBator(或 MyBatis + MYBatisGenerator)等工具创建和维护。

  • 包含丰富域对象的更高级别的层:这些对象中的每一个通常都是上述 POJO的。通过调用相应的 DAO,这些类还具有加载/保存图形的智能(可能是懒惰的,可能带有一些脏标志)。然而,重要的是,这些丰富的域对象不会一对一地映射到 POJO 对象(或 DB 表),而是与域用例。每个图的“大小”是确定的(它不会无限增长),并且像特定类一样从外部使用。因此,并不是说您使用了一个丰富的Person类(具有一些不确定的相关对象图),而是多个用例或服务方法;相反,你有几个丰富的课程PersonWithAddreses,, PersonWithAllData...每个都包含一个特定的有限图,具有自己的持久性逻辑。这可能看起来效率低下或笨拙,在某些情况下可能是这样,但经常发生的是,当您需要保存完整的对象图时,用例实际上是有限的。

  • 此外,对于表格报告之类的东西,(返回一堆要显示的列的特定 SELECTS)你不会使用上面的,而是直接和愚蠢的 POJO(甚至地图)

See my related answer here

在此处查看我的相关答案

回答by Lukas Eder

The answer to your many questions is simple. You have three choices.

您的许多问题的答案很简单。你有三个选择。

  1. Use one of the three SQL-centric tools you've mentioned (MyBatis, jOOQ, DbUtils). This means you should stop thinking in terms of your OO domain model and Object-Relational Mapping (i.e. entities and lazy loading). SQL is about relational data and RBDMS are pretty good at calculating execution plans for "eager fetching" the result of several joins. Usually, there isn't even a lot of need for premature caching, and if you do need to cache the occasional data element, you can still use something like EhCache

  2. Don't use any of those SQL-centric tools and stick with Hibernate / JPA. Because even if you said you don't like Hibernate, you're "thinking Hibernate". Hibernate is very good at persisting object graphs to the database. None of those tools can be forced to work like Hibernate, because their mission is something else. Their mission is to operate on SQL.

  3. Go an entirely different way and choose not to use a relational data model. Other data models (graphs for instance) may better suit you. I'm putting this as a third option, because you might not actually have that choice, and I don't have much personal experience with alternative models.

  1. 使用您提到的三个以 SQL 为中心的工具之一(MyBatisjOOQDbUtils)。这意味着您应该停止考虑 OO 域模型和对象关系映射(即实体和延迟加载)。SQL 是关于关系数据的,而 RBDMS 非常擅长计算“急切地获取”多个连接结果的执行计划。通常,甚至不需要太多的过早缓存,如果您确实需要缓存偶尔的数据元素,您仍然可以使用类似EhCache 的东西

  2. 不要使用任何以 SQL 为中心的工具并坚持使用 Hibernate/JPA。因为即使你说你不喜欢 Hibernate,你也在“考虑 Hibernate”。Hibernate 非常擅长将对象图持久化到数据库中。这些工具都不能被迫像 Hibernate 一样工作,因为它们的任务是别的。他们的任务是对 SQL 进行操作。

  3. 采取完全不同的方式并选择不使用关系数据模型。其他数据模型(例如图形)可能更适合您。我将此作为第三种选择,因为您实际上可能没有那个选择,而且我对替代模型没有太多个人经验。

Note, your question wasn't specifically about jOOQ. Nonetheless, with jOOQ, you can externalise the mapping of flat query results (produced from joined table sources) to object graphs through external tools such as ModelMapper. There's an intersting ongoing thread about such an integration on the ModelMapper User Group.

请注意,您的问题并不是专门针对 jOOQ。尽管如此,使用 jOOQ,您可以通过外部工具(如ModelMapper)将平面查询结果(从连接表源生成)映射到对象图。在ModelMapper User Group上有一个关于这种集成的有趣线程。

(disclaimer: I work for the company behind jOOQ)

(免责声明:我为 jOOQ 背后的公司工作)

回答by Glen Best

Persistence Approaches

持久性方法

The spectrum of solutions from simple/basic to sophisticated/rich is:

从简单/基本到复杂/丰富的解决方案范围是:

  • SQL/JDBC - hard-code SQL within objects
  • SQL-Based Framework (e.g. jOOQ, MyBatis) - Active Record Pattern (separate general object represents row data and handles SQL)
  • ORM-Framework (e.g. Hibernate, EclipseLink, DataNucleus) - Data Mapper Pattern (Object per Entity) plus Unit Of Work Pattern (Persistence Context / Entity Manager)
  • SQL/JDBC - 对象内的硬编码 SQL
  • SQL-Based Framework (eg jOOQ, MyBatis) - Active Record Pattern(单独的通用对象代表行数据并处理SQL)
  • ORM 框架(例如 Hibernate、EclipseLink、DataNucleus)——数据映射器模式(每个实体的对象)加上工作单元模式(持久性上下文/实体管理器)

You seek to implement one of the first two levels. That means shifting focus away from the object model towards SQL. But your question asks for Use Cases involving the object model being mapped to SQL (i.e. ORM behaviour). You wish to add functionality from the third level against functionality from one of the first two levels.

您寻求实施前两个级别之一。这意味着将焦点从对象模型转移到 SQL。但是您的问题要求涉及对象模型映射到 SQL(即 ORM 行为)的用例。您希望针对前两个级别之一的功能添加第三级的功能。

We could try to implement this behaviour within an Active Record. But this would need rich metadata to be attached to each Active Record instance - the actual entity involved, it's relationships to other entities, the lazy-loading settings, the cascade update settings. This would make it effectively a mapped entity object in hiding. Besides, jOOQ and MyBatis don't do this for Use Cases 1 & 2.

我们可以尝试在 Active Record 中实现这种行为。但这需要将丰富的元数据附加到每个 Active Record 实例 - 涉及的实际实体、它与其他实体的关系、延迟加载设置、级联更新设置。这将使它有效地成为隐藏的映射实体对象。此外,对于用例 1 和 2,jOOQ 和 MyBatis 不会这样做。

How To Achieve Your Requests?

如何实现您的要求?

Implement narrow ORM behaviour directly into your objects, as a small custom layer on top of your framework or raw SQL/JDBC.

将窄 ORM 行为直接实施到您的对象中,作为框架或原始 SQL/JDBC 之上的一个小型自定义层。

Use Case 1: Store metadata for each entity object relationship: (i) whether relationship should be lazy-loaded (class-level) and (ii) whether lazy-load has occured (object-level). Then in the getter method, use these flags to determine whether to do lazy-load and actually do it.

用例 1:为每个实体对象关系存储元数据:(i)关系是否应该延迟加载(类级别)和(ii)是否发生延迟加载(对象级别)。然后在getter方法中,使用这些标志来判断是否做lazy-load并实际做。

Use Case 2: Similar to Use Case 1 - do it yourself. Store a dirty flag within each entity. Against each entity object relationship, store a flag describing whether the save should be cascaded. Then when an entity is saved, recursively visit each "save cascade" relationship. Write any dirty entities discovered.

用例 2:类似于用例 1 - 自己动手。在每个实体中存储一个脏标志。针对每个实体对象关系,存储一个描述是否应该级联保存的标志。然后当一个实体被保存时,递归访问每个“保存级联”关系。写下发现的任何脏实体。

Patterns

图案

Pros

优点

  • Calls to SQL framework are simple.
  • 对 SQL 框架的调用很简单。

Cons

缺点

  • Your objects become more complicated. Take a look at the code for Use Cases 1 & 2 within an open source product. It's not trivial
  • Lack of support for Object Model. If you're using object model in java for your domain, it will have lesser support for data operations.
  • Risk of scope creep & anti-patterns: the above missing functionality is the tip of the iceberg. May end up doing some Reinvent the Wheel & Infrastructure Bloat in Business Logic.
  • Education and Maintenance on non-standard solution. JPA, JDBC and SQL are standards. Other frameworks or custom solutions aren't.
  • 您的对象变得更加复杂。查看开源产品中用例 1 和 2 的代码。这不是小事
  • 缺乏对对象模型的支持。如果您在域中使用 Java 中的对象模型,它将对数据操作的支持较少。
  • 范围蔓延和反模式的风险:上述缺失的功能只是冰山一角。可能最终会在业务逻辑中进行一些重新发明轮子和基础设施膨胀。
  • 非标准解决方案的教育和维护。JPA、JDBC 和 SQL 是标准。其他框架或自定义解决方案不是。

Worthwhile???

值得吗???

This solution works well if you have fairly simple data handling requirements and a data model with a smaller number of entities:

如果您有相当简单的数据处理要求和具有较少实体数量的数据模型,则此解决方案很有效:

  • If so, great! Do above.
  • If not, this solution's a poor fit and represents false savings in effort - i.e. will end up taking longer and being more complicated than using an ORM. In that case, have another look at JPA - it might be simpler than you think and it supports ORM for CRUD plus raw SQL for complicated queries :-).
  • 如果是这样,太好了!做上面。
  • 如果不是,则此解决方案不合适,并且表示错误地节省了工作量 - 即最终将花费更长的时间并且比使用 ORM 更复杂。在这种情况下,再看看 JPA - 它可能比您想象的更简单,它支持 CRUD 的 ORM 以及复杂查询的原始 SQL :-)。

回答by Beryllium

The last ten years I was using JDBC, EJB entity beans, Hibernate, GORM and finally JPA (in this order). For my current project I have returned to using plain JDBC, because the emphasis is on performance. Therefore I wanted

在过去的十年里,我使用了 JDBC、EJB 实体 bean、Hibernate、GORM,最后是 JPA(按此顺序)。对于我当前的项目,我已经重新使用普通 JDBC,因为重点是性能。因此我想要

  • Full control on the generationof SQL statements: To be able to pass a statement to DB performance tuners, and put the optimized version back in the program
  • Full control on the numberof SQL statements which are sent to the database
  • Stored procedures (triggers), stored functions (for complex calculations in SQL queries)
  • To be able to use all available SQL features without restrictions (recursive queries with CTEs, window aggregate functions, ...)
  • 完全控制SQL语句的生成:能够将语句传递给DB性能调优器,并将优化后的版本放回程序中
  • 完全控制发送到数据库的 SQL 语句的数量
  • 存储过程(触发器)、存储函数(用于 SQL 查询中的复杂计算)
  • 为了能够不受限制地使用所有可用的 SQL 功能(使用 CTE 的递归查询、窗口聚合函数等)

The data model is defined in a data dictionary; using a model driven approach a generator creates helper classes, DDL scripts etc. Most operations on the database are read-only; only few use cases write.

数据模型定义在数据字典中;使用模型驱动的方法,生成器创建辅助类、DDL 脚本等。数据库上的大多数操作都是只读的;只有少数用例写。

Question 1: Fetching children

问题一:接孩子

The system is built on a use cases, and we have one dedicatedSQL statement to get all data for a given use case/request. Some of the SQL statments are bigger than 20kb, they join, calculate using stored functions written in Java/Scala, sort, paginate etc. in a way that the result is directly mapped into a data transfer object which in turn is fed into the view (no further processing in the application layer). As a consequence the data transfer object is use case specific as well. It only contains the data for the given use case (nothing more, nothing less).

该系统建立在一个用例上,我们有一个专用的SQL 语句来获取给定用例/请求的所有数据。一些 SQL 语句大于 20kb,它们使用用 Java/Scala 编写的存储函数进行连接、计算、排序、分页等,结果直接映射到数据传输对象中,然后将其输入到视图中(在应用层没有进一步的处理)。因此,数据传输对象也是特定于用例的。它只包含给定用例的数据(不多也不少)。

As the result set is already "fully joined" there is no need for lazy/eager fetching etc. The data transfer object is complete. A cache is not needed (the database cache is fine); the exception: If the result set is large (around 50 000 rows), the data transfer object is used as a cache value.

由于结果集已经“完全连接”,因此不需要延迟/急切获取等。数据传输对象已完成。不需要缓存(数据库缓存就可以);例外:如果结果集很大(大约 50 000 行),则数据传输对象用作缓存值。

Question 2: Saving

问题 2:保存

After the controller has merged back the changes from the GUI, again there is a specific object which holds the data: Basically the rows with a state (new, deleted, modified, ...) in a hierarchy. It's a manual iteration to save the data down the hierarchy: New or modified data is persisted using some helper classes with generate SQL insertor updatecommands. As for deleted items, this is optimized into cascaded deletes (PostgreSql). If multiple rows are to be deleted, this is optimized into a single delete ... where id in ...statement as well.

在控制器从 GUI 合并回更改后,再次有一个特定对象保存数据:基本上是层次结构中具有状态(新的、删除的、修改的……)的行。这是将数据保存到层次结构中的手动迭代:使用一些带有生成 SQLinsertupdate命令的帮助程序类来持久保存新的或修改过的数据。至于删除的项目,这被优化为级联删除(PostgreSql)。如果要删除多行,这也被优化为单个delete ... where id in ...语句。

Again this is use case specific, so it's not dealing with a general approch. It needs more lines of code, but these are the lines which contain the optimizations.

同样,这是特定于用例的,因此它不涉及一般方法。它需要更多的代码行,但这些是包含优化的行。

The experiences so far

迄今为止的经历

  • One should not underestimate the effort to learn Hibernate or JPA. One should consider the time spent in configuring the caches, cache invalidation in a cluster, eager/lazy fetching, and tuning as well. Migrating to another Hibernate major version is not just a recompilation.
  • One should not overestimate the effort to build an application without ORM.
  • It's simpler to use SQL directly - being closeto SQL (like HQL, JPQL) is notthe same, especially if you talk to your DB performance tuner
  • SQL servers are incredibly fast when running long and complex queries, especially if combined with stored functions written in Scala
  • Even with the use case specific SQL statements, the code size is smaller: "Fully joined" result sets save lots of lines in the application layer.
  • 不应低估学习 Hibernate 或 JPA 的努力。应该考虑配置缓存、集群中的缓存失效、急切/延迟获取和调优所花费的时间。迁移到另一个 Hibernate 主要版本不仅仅是重新编译。
  • 不应高估在没有 ORM 的情况下构建应用程序的努力。
  • 直接使用 SQL 更简单 -接近SQL(如 HQL、JPQL)是一样的,尤其是当你和你的数据库性能调优器交谈时
  • SQL 服务器在运行长而复杂的查询时速度非常快,尤其是与用 Scala 编写的存储函数结合使用时
  • 即使使用特定于用例的 SQL 语句,代码大小也更小:“完全连接”结果集在应用程序层节省了大量行。

Related information:

相关信息:

Update: Interfaces

更新:接口

If there is a Personentity in the logical data model, there is a class to persist a Personentity (for CRUD operations), just like a JPA entity.

如果Person逻辑数据模型中有实体,则有一个类来持久化Person实体(用于 CRUD 操作),就像 JPA 实体一样。

But the clou is that there is no single Personentity from the use case / query / business logic perspective: Each service method defines its ownnotion of a Person, and it only contains exactlythe values required by that use case. Nothing more, nothing less. We use Scala, so the definition and usage of many small classes is very efficient (no setter/getter boiler plate code required).

但中心思想是,没有单一的Person从使用情况/查询/业务逻辑的角度来看实体:每个服务方法定义了它自己的概念Person,它仅包含正是由使用情况下所需的值。不多也不少。我们使用Scala,所以很多小类的定义和使用非常高效(不需要setter/getter样板代码)。

Example:

例子:

class GlobalPersonUtils {
  public X doSomeProcessingOnAPerson(
    Person person, PersonAddress personAddress, PersonJob personJob, 
    Set<Person> personFriends, ...)
}

is replaced by

被替换为

class Person {
  List addresses = ...
  public X doSomeProcessingOnAPerson(...)
}

class Dto {
  List persons = ...
  public X doSomeProcessingOnAllPersons()
  public List getPersons()
}

using use case specific Persons, Adressesetc: In this case, the Personalready aggregates all relevant data. Requires more classes, but there is no need to pass around JPA entities.

通过使用特定的情况下PersonsAdresses等:在这种情况下,Person已经汇集了所有相关数据。需要更多的类,但不需要传递 JPA 实体。

Note that this processing is read-only, the results are used by the view. Example: Get distinct Cityinstances from a person's list.

请注意,此处理是只读的,结果供视图使用。示例:City从一个人的列表中获取不同的实例。

If data is changed, this is another use case: If the city of a person is changed, this is processed by a different service method, and the person is fetched again from the database.

如果数据发生变化,这是另一个用例:如果一个人的城市发生了变化,则通过不同的服务方法进行处理,并再次从数据库中获取该人。

回答by Archie

Warning: This is another shameless plug from a project author.

警告:这是另一个来自项目作者的无耻插件。

Check out JSimpleDBand see if it meets your criteria of simplicity vs. power. This is a new project born out of 10+ years of frustration trying to deal with Java persistence via SQL and ORM.

查看JSimpleDB,看看它是否符合您的简单与强大的标准。这是一个新项目,它源于 10 多年试图通过 SQL 和 ORM 处理 Java 持久性的挫折。

It works on top of any database that can function as a key/value store, e.g., FoundationDB(or any SQL database, though everything will be jammed in a single key/value table).

它在任何可以用作键/值存储的数据库之上工作,例如FoundationDB(或任何 SQL 数据库,尽管所有内容都将卡在单个键/值表中)。

回答by CurtainDog

It sounds like the core issue in the question is with the relational model itself. From what's been described a graph database will map the problem domain very neatly. As an alternative, document stores are another way of approaching the problem because, while the impedance is still there, documents in general are simpler to reason about than sets. Of course, any approach is going to have its own quirks to attend to.

听起来这个问题的核心问题是关系模型本身。从所描述的内容来看,图形数据库将非常巧妙地映射问题域。作为替代方案,文档存储是解决问题的另一种方法,因为虽然阻抗仍然存在,但文档通常比集合更容易推理。当然,任何方法都会有自己的怪癖需要注意。

回答by Mladen Adamovic

Since you want a simple and lightweight library and to use SQL, I can suggest take a look at fjorm. It allows you to use POJOs and CRUD operations without much effort.

由于您想要一个简单而轻量级的库并使用 SQL,我建议您查看fjorm。它允许您毫不费力地使用 POJO 和 CRUD 操作。

Disclaimer: I'm an author of the project.

免责声明:我是该项目的作者。