fix(education): atomically read collection questions

This commit is contained in:
2026-07-31 11:23:09 +08:00
parent b569371005
commit b531be0d5b
2 changed files with 35 additions and 15 deletions

View File

@@ -47,6 +47,32 @@ public interface QuestionMapper extends BaseMapperX<QuestionDO> {
@Param("tenantId") Long tenantId, @Param("nodeId") Long nodeId,
@Param("type") String type, @Param("difficulty") String difficulty);
@Select("""
<script>
SELECT q.* FROM education_question_collection_question membership
JOIN education_question_collection collection ON collection.id=membership.collection_id
JOIN education_content_node node ON node.id=collection.node_id
JOIN education_content_entry entry ON entry.id=node.entry_id
JOIN education_question q ON q.id=membership.question_id
WHERE membership.collection_id=#{collectionId} AND membership.deleted=false
AND ((membership.tenant_id=#{tenantId} AND membership.scope='TENANT_OWNED') OR (membership.tenant_id=0 AND membership.scope='PUBLIC'))
AND collection.deleted=false AND collection.publication_status='ACTIVE' AND collection.is_active=true AND collection.is_hidden=false
AND ((collection.tenant_id=#{tenantId} AND collection.scope='TENANT_OWNED') OR (collection.tenant_id=0 AND collection.scope='PUBLIC'))
AND node.deleted=false AND node.publication_status='ACTIVE' AND node.is_active=true AND node.is_hidden=false
AND ((node.tenant_id=#{tenantId} AND node.scope='TENANT_OWNED') OR (node.tenant_id=0 AND node.scope='PUBLIC'))
AND entry.deleted=false AND entry.is_active=true AND entry.is_hidden=false
AND ((entry.tenant_id=#{tenantId} AND entry.scope='TENANT_OWNED') OR (entry.tenant_id=0 AND entry.scope='PUBLIC'))
AND q.deleted=false AND q.status='PUBLISHED' AND q.is_published=true
AND ((q.tenant_id=#{tenantId} AND q.scope='TENANT_OWNED') OR (q.tenant_id=0 AND q.scope='PUBLIC'))
<if test="type != null and type != ''">AND q.type=#{type}</if>
<if test="difficulty != null and difficulty != ''">AND q.difficulty=#{difficulty}</if>
ORDER BY membership.sort_order,membership.id
</script>
""")
IPage<QuestionDO> selectPublishedPageByAvailableCollection(IPage<QuestionDO> page,
@Param("tenantId") Long tenantId, @Param("collectionId") Long collectionId,
@Param("type") String type, @Param("difficulty") String difficulty);
default IPage<QuestionDO> selectPublishedPageByIds(IPage<QuestionDO> page, Long tenantId, List<Long> ids,
String type, String difficulty) {
if (ids == null || ids.isEmpty()) {

View File

@@ -47,7 +47,6 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
private final QuestionCollectionMapper questionCollectionMapper;
private final QuestionMapper questionMapper;
private final PracticeBlueprintMapper practiceBlueprintMapper;
private final QuestionCollectionQuestionMapper collectionQuestionMapper;
public JavaCatalogProvider(EducationProperties properties,
RegionMapper regionMapper,
@@ -59,8 +58,7 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
ContentNodeMapper contentNodeMapper,
QuestionCollectionMapper questionCollectionMapper,
QuestionMapper questionMapper,
PracticeBlueprintMapper practiceBlueprintMapper,
QuestionCollectionQuestionMapper collectionQuestionMapper) {
PracticeBlueprintMapper practiceBlueprintMapper) {
this.properties = properties;
this.regionMapper = regionMapper;
this.schoolMapper = schoolMapper;
@@ -72,7 +70,6 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
this.questionCollectionMapper = questionCollectionMapper;
this.questionMapper = questionMapper;
this.practiceBlueprintMapper = practiceBlueprintMapper;
this.collectionQuestionMapper = collectionQuestionMapper;
}
@Override
@@ -157,10 +154,9 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
int pageNo, int pageSize) {
Long cid = parseOptionalLong(collectionId); Long nid = parseOptionalLong(nodeId);
int bounded = clampPageSize(pageSize); int page = pageNo > 0 ? pageNo : 1;
List<Long> ids = cid == null ? null : readWithExplicitCatalogScope(() -> collectionQuestionMapper.selectByCollectionId(tenantId(), cid)).stream()
.map(QuestionCollectionQuestionDO::getQuestionId).toList();
IPage<QuestionDO> result = ids != null
? readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByIds(new Page<>(page, bounded), tenantId(), ids, type, difficulty))
IPage<QuestionDO> result = cid != null
? readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByAvailableCollection(
new Page<>(page, bounded), tenantId(), cid, type, difficulty))
: nid != null
? readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByAvailableNode(
new Page<>(page, bounded), tenantId(), nid, type, difficulty))
@@ -172,9 +168,8 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
@Override
public CatalogQuestionPageResult listCollectionQuestions(String collectionId, String type, String difficulty, int pageNo, int pageSize) {
Long cid = parseRequiredLong(collectionId); int page = pageNo > 0 ? pageNo : 1;
List<Long> ids = readWithExplicitCatalogScope(() -> collectionQuestionMapper.selectByCollectionId(tenantId(), cid)).stream()
.map(QuestionCollectionQuestionDO::getQuestionId).toList();
IPage<QuestionDO> result = readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByIds(new Page<>(page, clampPageSize(pageSize)), tenantId(), ids, type, difficulty));
IPage<QuestionDO> result = readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByAvailableCollection(
new Page<>(page, clampPageSize(pageSize)), tenantId(), cid, type, difficulty));
return buildPageResult(result);
}
@@ -234,10 +229,9 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv
}
private long countVisibleCollectionQuestions(Long collectionId, String type, String difficulty) {
List<Long> ids = readWithExplicitCatalogScope(() -> collectionQuestionMapper
.selectByCollectionId(tenantId(), collectionId)).stream()
.map(QuestionCollectionQuestionDO::getQuestionId).toList();
return readWithExplicitCatalogScope(() -> questionMapper.countPublishedByIds(tenantId(), ids, type, difficulty));
IPage<QuestionDO> page = readWithExplicitCatalogScope(() -> questionMapper.selectPublishedPageByAvailableCollection(
new Page<>(1, 1), tenantId(), collectionId, type, difficulty));
return page.getTotal();
}
private long countVisibleNodeQuestions(Long nodeId, String type, String difficulty) {