组懒加载

This commit is contained in:
2026-08-28 10:20:17 +08:00
parent e027a033b4
commit afbd19522e
4 changed files with 48 additions and 29 deletions
@@ -42,6 +42,8 @@ public interface SchClassRepository extends JpaRepository<SchClass, Integer>, Jp
@Param("keyword") String keyword, @Param("keyword") String keyword,
Pageable pageable); Pageable pageable);
boolean existsBySchIdAndGroupIdAndName(Integer schId, Integer groupId, String name); boolean existsBySchIdAndGroupIdAndName(Integer schId, Integer groupId, String name);
boolean existsBySchIdAndGroupIdAndNameAndIdNot(Integer schId, Integer groupId, String name, Integer id); boolean existsBySchIdAndGroupIdAndNameAndIdNot(Integer schId, Integer groupId, String name, Integer id);
@@ -56,6 +58,15 @@ public interface SchClassRepository extends JpaRepository<SchClass, Integer>, Jp
List<SchClass> findBySchIdAndEnrollYear(Integer schId, Integer enrollYear); List<SchClass> findBySchIdAndEnrollYear(Integer schId, Integer enrollYear);
/**
* 根据学校ID和班级组ID列表查询班级
* @param schId 学校ID
* @param classIds 班级组ID列表(group_class_id,即 SchClass.classId)
* @return 匹配的班级列表(与入参顺序无关,按库内顺序返回)
*/
@Query("SELECT c FROM SchClass c WHERE c.schId = :schId AND c.classId IN :classIds")
List<SchClass> findBySchIdAndClassIds(@Param("schId") Integer schId, @Param("classIds") List<Integer> classIds);
boolean existsBySchIdAndClassId(Integer schId, Integer classId); boolean existsBySchIdAndClassId(Integer schId, Integer classId);
@Query("SELECT COUNT(c) FROM SchClass c WHERE (c.firstTeacherId IN (:ids) OR c.secondTeacherId IN (:ids)) AND c.schId = :schId AND c.graduate = 0") @Query("SELECT COUNT(c) FROM SchClass c WHERE (c.firstTeacherId IN (:ids) OR c.secondTeacherId IN (:ids)) AND c.schId = :schId AND c.graduate = 0")
@@ -23,6 +23,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@@ -77,7 +78,7 @@ public class ComSchTreeService implements IComSchTreeService {
synchronized (lock) { synchronized (lock) {
baseSchsystemMap = null; baseSchsystemMap = null;
} }
idToNameCache = null; idToNameCacheBySchId.clear();
} }
/** /**
@@ -316,38 +317,25 @@ public class ComSchTreeService implements IComSchTreeService {
public String getTeaGroupName(Integer schId, Integer id) { public String getTeaGroupName(Integer schId, Integer id) {
BoaGroup tree = getTeaTree(schId,true); if (id == null) return null;
if (tree == null) return null; return getTeaNameCache(schId).get(id);
// 懒加载缓存(若树结构不变)
if (idToNameCache == null) {
idToNameCache = new HashMap<>();
buildCache(tree);
}
return idToNameCache.get(id);
} }
public List<SelectIntVO> getTeaGroupNameList(Integer schId, List<Integer> ids) { public List<SelectIntVO> getTeaGroupNameList(Integer schId, List<Integer> ids) {
// 1. 构建缓存(如果尚未构建) // 1. 获取当前学校的组名缓存(按 schId 懒加载,不跨学校串用)
if (idToNameCache == null) { Map<Integer, String> cache = getTeaNameCache(schId);
BoaGroup tree = getTeaTree(schId,true);
if (tree == null) {
return Collections.emptyList();
}
idToNameCache = new HashMap<>();
buildCache(tree);
}
// 2. 如果缓存为空,直接返回空 // 2. 如果缓存为空,直接返回空
if (idToNameCache.isEmpty()) { if (cache.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
// 3. 处理 ids 参数 // 3. 处理 ids 参数
List<Integer> targetIds; List<Integer> targetIds;
if (ids == null) { if (ids == null) {
// 如果 ids 为 null,返回全部(从缓存中取出所有 key) // 如果 ids 为 null,返回全部(从当前学校缓存中取出所有 key)
targetIds = new ArrayList<>(idToNameCache.keySet()); targetIds = new ArrayList<>(cache.keySet());
} else { } else {
// 过滤掉 null 的 ID,并去重(可选) // 过滤掉 null 的 ID,并去重(可选)
targetIds = ids.stream() targetIds = ids.stream()
@@ -362,7 +350,7 @@ public class ComSchTreeService implements IComSchTreeService {
// 4. 根据 targetIds 构建结果列表 // 4. 根据 targetIds 构建结果列表
List<SelectIntVO> result = new ArrayList<>(); List<SelectIntVO> result = new ArrayList<>();
for (Integer id : targetIds) { for (Integer id : targetIds) {
String name = idToNameCache.get(id); String name = cache.get(id);
if (name != null) { if (name != null) {
SelectIntVO vo = new SelectIntVO(); SelectIntVO vo = new SelectIntVO();
vo.setId(id); vo.setId(id);
@@ -933,14 +921,34 @@ public class ComSchTreeService implements IComSchTreeService {
} }
} }
private Map<Integer, String> idToNameCache; /**
* 教师组树 id->name 缓存,按学校分桶,避免跨学校串数据
* 组树变更后需调用 clearCache() 清空(同一学校内部结构变化也会失效)
*/
private final Map<Integer, Map<Integer, String>> idToNameCacheBySchId = new ConcurrentHashMap<>();
private void buildCache(BoaGroup node) { /**
* 获取指定学校的组名缓存(懒加载:首次按 schId 构建;树为 null 时不落缓存,下次重试)
*/
private Map<Integer, String> getTeaNameCache(Integer schId) {
Map<Integer, String> cache = idToNameCacheBySchId.get(schId);
if (cache == null) {
BoaGroup tree = getTeaTree(schId, true);
cache = new HashMap<>();
if (tree != null) {
buildCache(tree, cache);
idToNameCacheBySchId.put(schId, cache);
}
}
return cache;
}
private void buildCache(BoaGroup node, Map<Integer, String> cache) {
if (node == null) return; if (node == null) return;
idToNameCache.put(node.getId(), node.getName()); cache.put(node.getId(), node.getName());
if (node.getChildren() != null) { if (node.getChildren() != null) {
for (BoaGroup child : node.getChildren()) { for (BoaGroup child : node.getChildren()) {
buildCache(child); buildCache(child, cache);
} }
} }
} }
@@ -250,7 +250,7 @@ public class SchStudentLogService {
try { try {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
// 1. 批量查询班级名称 // 1. 批量查询班级名称
List<SchClass> classList = schClassRepository.findAllById(affectedClassIds); List<SchClass> classList = schClassRepository.findBySchIdAndClassIds(user.getSchId(),affectedClassIds.stream().collect(Collectors.toList()));
Map<Integer, SchClass> classMap = classList.stream() Map<Integer, SchClass> classMap = classList.stream()
.collect(Collectors.toMap(SchClass::getClassId, Function.identity())); .collect(Collectors.toMap(SchClass::getClassId, Function.identity()));
Map<Integer, String> gradeNameMap = baseSchsystemGradeService.getGradeNameMap(user.getSchId(), null, null); Map<Integer, String> gradeNameMap = baseSchsystemGradeService.getGradeNameMap(user.getSchId(), null, null);
@@ -330,7 +330,7 @@ public class SchStudentLogService {
// 查询原班级名称(可能跨校) // 查询原班级名称(可能跨校)
String originalClassName = "未知班级"; String originalClassName = "未知班级";
if (originalSchId != null && originalClassId != null) { if (originalSchId != null && originalClassId != null) {
SchClass originalClass = schClassRepository.findByIdAndSchId(originalClassId, originalSchId).orElse(null); SchClass originalClass = schClassRepository.findByClassIdAndSchId(originalClassId, originalSchId).orElse(null);
if (originalClass != null) { if (originalClass != null) {
originalClassName = gradeMap.get(originalClass.getGradeId()) + originalClass.getName(); originalClassName = gradeMap.get(originalClass.getGradeId()) + originalClass.getName();
} }
@@ -139,7 +139,7 @@ public class SchStudentTransferService {
throw new DException("以下学生不存在或不属于该校: " + missing); throw new DException("以下学生不存在或不属于该校: " + missing);
} }
List<Integer> syncStuIds=students.stream().map(s->s.getStuId()).collect(Collectors.toList()); // List<Integer> syncStuIds=students.stream().map(s->s.getStuId()).collect(Collectors.toList());
// 收集受影响的班级ID // 收集受影响的班级ID
Set<Integer> classIds = students.stream() Set<Integer> classIds = students.stream()