From bd956bcb35431512605f0837e6b8eb527948bc3a Mon Sep 17 00:00:00 2001 From: wangziqi Date: Fri, 31 Jul 2026 16:26:39 +0800 Subject: [PATCH] fix(education): tighten entitlement integration contracts --- .../commercialization/EducationEntitlementMapper.java | 3 +++ .../integration/member/MemberPointAwardPort.java | 4 +++- .../EducationEntitlementServiceImpl.java | 2 ++ .../ResourceProductBindingService.java | 3 ++- .../module/member/api/point/MemberPointBizType.java | 10 ++++++++++ .../member/enums/point/MemberPointBizTypeEnum.java | 3 ++- 6 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointBizType.java diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/dal/mysql/commercialization/EducationEntitlementMapper.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/dal/mysql/commercialization/EducationEntitlementMapper.java index b487902c..75283cae 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/dal/mysql/commercialization/EducationEntitlementMapper.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/dal/mysql/commercialization/EducationEntitlementMapper.java @@ -9,6 +9,9 @@ import java.time.LocalDateTime; @Mapper public interface EducationEntitlementMapper extends BaseMapperX { + @Select("SELECT 1 FROM pg_advisory_xact_lock(hashtextextended(#{subjectKey}, 0))") + Integer lockSubject(@Param("subjectKey") String subjectKey); + @Select(""" SELECT * FROM education_entitlement WHERE tenant_id=#{tenantId} AND user_id=#{userId} AND resource_type=#{resourceType} AND resource_id=#{resourceId} diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/integration/member/MemberPointAwardPort.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/integration/member/MemberPointAwardPort.java index befd3508..f830376c 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/integration/member/MemberPointAwardPort.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/integration/member/MemberPointAwardPort.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.education.integration.member; import cn.iocoder.yudao.module.member.api.point.MemberPointApi; +import cn.iocoder.yudao.module.member.api.point.MemberPointBizType; import org.springframework.stereotype.Component; /** @@ -16,7 +17,8 @@ public class MemberPointAwardPort { } public void addLearningPoints(Long userId, Integer points, Long awardId) { - memberPointApi.addPoint(userId, points, 31, "education-learning-award:" + awardId); + memberPointApi.addPoint(userId, points, MemberPointBizType.EDUCATION_LEARNING, + "education-learning-award:" + awardId); } } diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/EducationEntitlementServiceImpl.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/EducationEntitlementServiceImpl.java index 5ed5be6c..84eba6ab 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/EducationEntitlementServiceImpl.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/EducationEntitlementServiceImpl.java @@ -42,6 +42,8 @@ public class EducationEntitlementServiceImpl implements EducationEntitlementServ } return existing.getEntitlementId(); } + entitlementMapper.lockSubject(tenantId + ":" + command.userId() + ":" + command.resourceType() + + ":" + command.resourceId()); EducationEntitlementDO aggregate = entitlementMapper.selectForUpdate(tenantId, command.userId(), command.resourceType(), command.resourceId()); boolean applied; if ("GRANT".equals(command.eventType())) { diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/ResourceProductBindingService.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/ResourceProductBindingService.java index 56dc3fc5..6a15019e 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/ResourceProductBindingService.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/commercialization/ResourceProductBindingService.java @@ -38,10 +38,11 @@ public class ResourceProductBindingService { throw exception(PRODUCT_BINDING_CONFLICT); } else if (!"ACTIVE".equals(existing.getStatus())) { int version = existing.getVersion(); - bindingMapper.update(null, new LambdaUpdateWrapper() + int updated = bindingMapper.update(null, new LambdaUpdateWrapper() .eq(EducationResourceProductBindingDO::getId, existing.getId()).eq(EducationResourceProductBindingDO::getTenantId, tenantId) .eq(EducationResourceProductBindingDO::getVersion, version).set(EducationResourceProductBindingDO::getStatus, "ACTIVE") .set(EducationResourceProductBindingDO::getVersion, version + 1)); + if (updated != 1) throw exception(PRODUCT_BINDING_CONFLICT); existing.setStatus("ACTIVE"); existing.setVersion(version + 1); } return toResult(existing); diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointBizType.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointBizType.java new file mode 100644 index 00000000..dc87e811 --- /dev/null +++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointBizType.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.member.api.point; + +/** + * Public Member point business types available to other modules. + */ +public interface MemberPointBizType { + + int EDUCATION_LEARNING = 31; + +} diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java index 832fd705..c11e4cdc 100644 --- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java +++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.member.enums.point; import cn.hutool.core.util.EnumUtil; +import cn.iocoder.yudao.module.member.api.point.MemberPointBizType; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; @@ -27,7 +28,7 @@ public enum MemberPointBizTypeEnum implements ArrayValuable { ORDER_GIVE_CANCEL(22, "订单积分奖励(整单取消)", "订单取消,退还 {} 积分", false), // ORDER_GIVE 的取消 ORDER_GIVE_CANCEL_ITEM(23, "订单积分奖励(单个退款)", "订单退款,扣除赠送的 {} 积分", false), // ORDER_GIVE 的取消 - EDUCATION_LEARNING(31, "教育学习奖励", "完成学习任务获得 {} 积分", true) + EDUCATION_LEARNING(MemberPointBizType.EDUCATION_LEARNING, "教育学习奖励", "完成学习任务获得 {} 积分", true) ; /**