如果需求是根据自增主键 id
的排序来确定当前记录是第几条,以及计算符合条件的总记录数,我们可以对之前的设计进行适当的调整。这里,我们会修改 Repository 层的方法以确保基于 id
的排序,并更新 Service 层以反映这一变化。
Repository 层
修改 MmScenesContentRepository
接口,以确保查询结果根据 id
排序。我们假设你想要按照 id
升序排序所有记录:
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MmScenesContentRepository extends JpaRepository<MmScenesContent, Long> {
List<MmScenesContent> findByScenesIdOrderByIDAsc(Long scenesId);
}
Service 层
更新 MmScenesContentService
服务,利用 id
进行排序和定位计算。这里的逻辑是查找给定场景 scenesId
的所有内容,并按照 id
排序,然后确定特定 identifierId
的位置:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MmScenesContentService {
@Autowired
private MmScenesContentRepository repository;
public SceneContentInfo getSceneContentInfo(Long scenesId, String identifierId) {
List<MmScenesContent> contents = repository.findByScenesIdOrderByIDAsc(scenesId);
int position = 1; // 默认为第一条
if (identifierId != null) {
for (int i = 0; i < contents.size(); i++) {
if (contents.get(i).getIdentifierId().equals(identifierId)) {
position = i + 1;
break;
}
}
}
SceneContentInfo info = new SceneContentInfo(position, contents.size());
return info;
}
}
SceneContentInfo DTO
SceneContentInfo
DTO 不需要改变,因为它只是用来传输位置信息和总数。
Controller 层
Controller 层的代码也不需要改变,因为它只负责调用 Service 层的 getSceneContentInfo
方法并返回结果。
通过这种方式,我们确保了查询结果根据 id
的自增顺序进行排序,从而可以基于这个排序来计算每条记录的位置。这样,即使在并发创建记录的情况下,每个记录的位置也能正确地反映出它在数据库中的顺序。
确实,前面提出的优化虽然减少了应用层的负载,但引入了两次数据库查询,这对于某些情况下可能不是最佳选择,特别是当数据库查询成本较高时。一个更加优化的方案是尽量减少数据库查询的次数。
如果我们的目标是在单个查询中尽可能地完成工作,我们可以考虑使用原生 SQL 或 JPQL 来执行一个更复杂的查询,该查询旨在一次性返回我们需要的所有信息。不过,这种方法可能需要牺牲一些可读性和维护性,因为复杂的查询通常比简单的查询难以理解和维护。
下面提供一个理论上的解决方案,它基于单次查询来获取位置和总数,但实际实现将取决于你的数据库类型和具体架构。
Service 层
在这个示例中,我们假设能够通过某种方式一次性获取到位置和总数,这可能需要你根据实际使用的数据库来调整 SQL 语句。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MmScenesContentService {
@Autowired
private MmScenesContentRepository repository;
public SceneContentPageInfo getSceneContentInfo(Long scenesId, String identifierId) {
// 假设这个方法可以通过一个复杂的查询获取到所需的所有信息
SceneContentPageInfo pageInfo = repository.findPositionAndTotal(scenesId, identifierId);
return pageInfo;
}
}
Repository 层
你可能需要使用 @Query
注解来执行一个原生 SQL 查询,该查询能够一次性计算出特定记录的位置以及总数。具体的 SQL 语句将依赖于你的数据库类型(比如 MySQL, PostgreSQL 等),这里仅提供一个概念性的框架,实际的实现需要你根据自己的数据库结构和 SQL 能力进行设计。
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface MmScenesContentRepository extends JpaRepository<MmScenesContent, Long> {
@Query(value = "SELECT position, total FROM (SELECT id, RANK() OVER (ORDER BY id ASC) AS position, COUNT(*) OVER() AS total FROM mm_scenes_content WHERE scenes_id = :scenesId) AS subquery WHERE id = (SELECT id FROM mm_scenes_content WHERE identifier_id = :identifierId)", nativeQuery = true)
SceneContentPageInfo findPositionAndTotal(@Param("scenesId") Long scenesId, @Param("identifierId") String identifierId);
}
请注意,上面的 SQL 语句是伪代码,用于展示可能的查询结构。具体实现将需要根据你的数据库类型和需求调整。此外,SceneContentPageInfo
类可能需要相应地调整以映射查询结果。
这种方法尝试在单个查询中完成所有工作,减少了数据库访问次数,但代价是增加了查询的复杂性和对特定数据库特性的依赖。在实际应用中,你需要根据实际情况权衡使用简单查询与应用层处理相结合的方法,还是使用复杂的单次查询。