Apache Isis 列出实体的操作太慢,发现 2 个问题/疑问
使用演示应用程序 PetClinic 作为示例。仅关注 PetOwner,不关注其他实体。一些宠物主人已预先插入到数据库中。 演示中的操作“listAll”:
@Action(semantics = SemanticsOf.SAFE)
@ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
public List<PetOwner> listAll() {
return petOwnerRepository.findAll();
}
当调用操作“listAll”时,我们发现两个与延迟相关的问题。
- 发出大量查询,每个实体一个 这是对 jpa 的查询,这是有意义的
[EL Fine]: sql: 2022-03-10 14:50:50.303--ClientSession(1477740542)--Connection(716488272)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER
,并且还会有更多查询出现:
[EL Fine]: sql: 2022-03-10 14:50:50.436--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [1]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [2]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [3]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [4]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [5]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [6]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [7]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [8]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [9]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [10]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [11]
[EL Fine]: sql: 2022-03-10 14:50:50.44--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [12]
[EL Fine]: sql: 2022-03-10 14:50:50.44--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [13]
Apache Isis 内部是否有任何配置/设置来不进行这些查询?因为从第一个查询开始我就认为我们已经把一切都做好了?
- 即使没有这些查询,我们仍然会看到延迟。 因此,为了解决这个问题,我们引入了一个 DTO 类作为视图模型,以将域实体与列表结果
DTO 类解耦:
@DomainObject(nature = Nature.VIEW_MODEL,logicalTypeName = "cps.PetOwnerDtoViewModel")
@XmlRootElement(name = "PetOwnerDtoViewModel")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
propOrder = {
"name",
"notes"
}
)
public class PetOwnerDto {
private String name;
private String notes;
...(constructor and getter setter)
}
并将 DTO 列表包装到另一个视图模型中,因为我们需要稍后添加针对集合的操作。 (如此处建议的 ISIS:从已弃用的 @Action(invokeOn=...) @Action(associateWith=...))
@DomainObject(nature = Nature.VIEW_MODEL,logicalTypeName = "cps.PetOwnersViewModel")
@XmlRootElement(name = "PetOwnersViewModel")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
propOrder = {
"petOwnerList"
}
)
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public class PetOwnersViewModel {
public String title() {
return "Owners";
}
@XmlElementWrapper
@XmlElement(name = "petOwnerList")
@Getter
@Setter
@CollectionLayout(paged = 5)
protected List<PetOwnerDto> petOwnerList = new LinkedList<>();
public PetOwnersViewModel(List<PetOwnerDto> results) {
this.petOwnerList = results;
}
}
我们创建了一个新操作来返回 PetOwnerViewModel:
@Action(semantics = SemanticsOf.SAFE)
@ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
public PetOwnersViewModel listAllDto() {
List<PetOwner> petOwnerList = petOwnerRepository.findAll();
LinkedList<PetOwnerDto> petOwnerDtos = new LinkedList<>();
for (PetOwner p : petOwnerList) {
petOwnerDtos.add(new PetOwnerDto(p));
}
return new PetOwnersViewModel(petOwnerDtos);
}
这样只有一个查询会发送到db,没有发现额外的查询。 然后我们向数据库加载了 1000 个宠物主人。使用 @CollectionLayout(paged = 5)
时,延迟仍然存在但可以接受,但如果我们单击“显示全部”,则需要 20 秒才能显示所有 1000 行数据。这个操作需要这么长时间有什么原因吗?既然所有需要的数据都已经从数据库中提取了,对吧?
谢谢,希望有人能帮忙!
Use demo app PetClinic as an example. Only focus on PetOwner, no other entities. Some pet owners are pre-inserted to the db.
The action "listAll" in the demo:
@Action(semantics = SemanticsOf.SAFE)
@ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
public List<PetOwner> listAll() {
return petOwnerRepository.findAll();
}
When action "listAll" is called, we find two issues/questions related to the delay.
- Lots of queries are going out, one for each entity
this is the query goes to jpa that makes sense
[EL Fine]: sql: 2022-03-10 14:50:50.303--ClientSession(1477740542)--Connection(716488272)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER
and there are more queries coming:
[EL Fine]: sql: 2022-03-10 14:50:50.436--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [1]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [2]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [3]
[EL Fine]: sql: 2022-03-10 14:50:50.437--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [4]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [5]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [6]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [7]
[EL Fine]: sql: 2022-03-10 14:50:50.438--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [8]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [9]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [10]
[EL Fine]: sql: 2022-03-10 14:50:50.439--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [11]
[EL Fine]: sql: 2022-03-10 14:50:50.44--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [12]
[EL Fine]: sql: 2022-03-10 14:50:50.44--ClientSession(840311416)--Connection(1724151743)--SELECT id, NAME, NOTES, version FROM pets.PETOWNER WHERE (id = ?)
bind => [13]
is there any config/setting inside Apache Isis to not make those queries? since from the first query I assume we already got everything right?
- We still see delay even without those queries.
So to solve the issue, we introduced a DTO class as view model to decouple domain entities from the list results
DTO class:
@DomainObject(nature = Nature.VIEW_MODEL,logicalTypeName = "cps.PetOwnerDtoViewModel")
@XmlRootElement(name = "PetOwnerDtoViewModel")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
propOrder = {
"name",
"notes"
}
)
public class PetOwnerDto {
private String name;
private String notes;
...(constructor and getter setter)
}
and wrapped a list of DTOs into another viewmodel because we need to add action against collection later. (as suggested here ISIS: Moving from deprecated @Action(invokeOn=...) to @Action(associateWith=...))
@DomainObject(nature = Nature.VIEW_MODEL,logicalTypeName = "cps.PetOwnersViewModel")
@XmlRootElement(name = "PetOwnersViewModel")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
propOrder = {
"petOwnerList"
}
)
@NoArgsConstructor(access = AccessLevel.PUBLIC)
public class PetOwnersViewModel {
public String title() {
return "Owners";
}
@XmlElementWrapper
@XmlElement(name = "petOwnerList")
@Getter
@Setter
@CollectionLayout(paged = 5)
protected List<PetOwnerDto> petOwnerList = new LinkedList<>();
public PetOwnersViewModel(List<PetOwnerDto> results) {
this.petOwnerList = results;
}
}
And we created a new action to return PetOwnerViewModel:
@Action(semantics = SemanticsOf.SAFE)
@ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
public PetOwnersViewModel listAllDto() {
List<PetOwner> petOwnerList = petOwnerRepository.findAll();
LinkedList<PetOwnerDto> petOwnerDtos = new LinkedList<>();
for (PetOwner p : petOwnerList) {
petOwnerDtos.add(new PetOwnerDto(p));
}
return new PetOwnersViewModel(petOwnerDtos);
}
This way there is only one query goes out to db, no extra queries are found.
Then we loaded the db with 1000 pet owners. with @CollectionLayout(paged = 5)
in place, the delay is still there but acceptable, but if we click "show all", it takes 20 seconds to show all 1000 rows' data. Is there any reason this operation takes so long? Since all the needed data is already pulled from db right?
Thanks, hope anyone can help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正式来说,这不是一个答案(只是一条评论):
感谢您在这里报告您的观察结果!我确实打开了 Jira 票证以进行进一步调查:
https://issues.apache.org/ jira/浏览/ISIS-2973
Formally this is not an answer (just a comment):
Thanks for reporting your observations here! I did open a Jira ticket for further investigation:
https://issues.apache.org/jira/browse/ISIS-2973