我使用了Sping Boot 和QueryDSL。
当在ClientMemoRepositoryImpl.java
中调用findAllByWriterGroupByClient
方法时,[生成的查询1]生成一次,[生成的查询2]生成多次。
此外,当读取此查询的结果作为ClientMemoServiceImpl.java
中的元组时,会多次生成[生成的查询3]。
- ClientMemoRepositoryImpl.java
@Override
public List<Tuple> findAllByWriterGroupByClient(String searchKeyword, Long writerId, boolean hasAdminRole) {
QClientMemo qClientMemo1 = new QClientMemo("cm1");
QClientMemo qClientMemo2 = new QClientMemo("cm2");
JPAQuery<Tuple> memoDtoJPAQuery = qf.select(
JPAExpressions.selectFrom(qClientMemo1)
.where(qClientMemo1.clientId.eq(qClientMemo.clientId).and(
qClientMemo1.createdDate.eq(
JPAExpressions
.select(qClientMemo2.createdDate.max())
.from(qClientMemo2)
.where(qClientMemo2.clientId.eq(qClientMemo.clientId))
)
)
),
new CaseBuilder()
.when(qClientMemo.createdDate.gt(LocalDateTime.now().minusDays(7)))
.then(1)
.otherwise(0).sum()
)
.from(qClientMemo);
if ((!hasAdminRole) && writerId != null) {
memoDtoJPAQuery = memoDtoJPAQuery.where(qClientMemo.writer.id.eq(writerId));
}
if (searchKeyword != null)
memoDtoJPAQuery = memoDtoJPAQuery.where(
qClientMemo.title.contains(searchKeyword)
.or(qClientMemo.content.contains(searchKeyword))
.or(qClientMemo.clientId.clientName.contains(searchKeyword))
.or(qClientMemo.writer.name.contains(searchKeyword))
);
return memoDtoJPAQuery
.groupBy(qClientMemo.clientId)
.orderBy(OrderByNull.DEFAULT)
.fetch();
}
- 生成的查询1
select
(select
clientmemo1_.id
from
client_memo clientmemo1_
where
clientmemo1_.client_id=clientmemo0_.client_id
and clientmemo1_.created_date=(
select
max(clientmemo2_.created_date)
from
client_memo clientmemo2_
where
clientmemo2_.client_id=clientmemo0_.client_id
)
) as col_0_0_, sum(case
when clientmemo0_.created_date>? then ?
else 0
end) as col_1_0_
from
client_memo clientmemo0_
group by
clientmemo0_.client_id
order by
null asc
- 生成的查询2
select
[all fields of client_memo entity]
from
client_memo clientmemo0_
where
clientmemo0_.id=?
- 生成的查询3
select
[all fields of client entity]
from
client client0_
where
client0_.id=?
- ClientMemoServiceImpl.java
List<Tuple> clientMemos = clientMemoRepository.findAllByWriterGroupByClient(
readClientMemoDto.getSearchKeyword(),
readClientMemoDto.getUserId(),
hasAdminRole
);
clientMemos.forEach(clientMemo -> {
Map<String, Object> result = new HashMap<>();
Integer newCnt = clientMemo.get(1, Integer.class);
if (newCnt != null) {
result.put("newMemoNum", newCnt);
}
MemoDto memoDto = new MemoDto();
ClientMemo memo = clientMemo.get(0, ClientMemo.class);
if (memo != null) {
memoDto.ofClientMemo(memo);
result.put("memoDetail", memoDto);
}
results.add(result);
});
- ClientMemo.java
@Entity
@Table(name = "client_memo")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@DynamicInsert
public class ClientMemo {
@JsonIgnore
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "title", nullable = false)
private String title;
@Lob
@Column(name = "content")
private String content;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="client_id")
private Client clientId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="writer")
private User writer;
@Column(name = "created_date")
private LocalDateTime createdDate;
@Column(name = "updated_date")
private LocalDateTime updatedDate;
@Column(name = "is_admin")
private boolean isAdmin;
}
- Client.java
@Entity
@Table(name = "client")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@DynamicInsert
public class Client {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "client_name", nullable = false)
private String clientName;
@Column(name = "client_phone_num", nullable = false)
private String clientPhoneNum;
@Column(name = "service_start_time")
private LocalDateTime serviceStartTime;
@Column(name = "service_end_time")
private LocalDateTime serviceEndTime;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "media_id")
private Media media;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_charge_id")
private User personCharge;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "normal_memo")
private ClientMemo normalMemo;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "admin_memo")
private ClientMemo adminMemo;
@Column(name = "status", columnDefinition = "varchar(20) default 'UNCONTRACTED'")
@Enumerated(EnumType.STRING)
private ClientStatus status;
@Column(name = "is_deleted", nullable = false)
private boolean isDeleted;
}
数据关系的所有FetchType
都是FetchType.LAZY
。
我不明白为什么会出现这个问题,为什么有些人说使用FetchType.LAZY
比使用FetchType.EAGER
更好。
我对QueryDSL或SpringBoot的理解是否正确?
谢谢
1条答案
按热度按时间k5hmc34c1#
您应该与我们分享您的Jpa实体。
在我看来,你应该在你的实体中设置一些关联(@OneToMany等),可能是在Eager模式(默认模式)下。
当您尝试从数据库加载对象的一个示例时,Hibernate也会加载关联。在急切模式下,Hibernate通过查询数据库(这会生成额外的sql查询)来加载关联。
如果您在Lazy模式下定义关联,Hibernate将使用一些代理对象填充实体jpa,并在稍后获取关联,但仅在您访问关联时获取(这意味着,当您仅尝试在代码中访问关联时,关联的sql查询将被延迟)。