【基于SpringBoot和Mybatis-Plus的关联表关联关系保存和修改】

本项目是个微服务项目,采用前后端分离方式进行协作开发。需求描述:表A和和表B通过equity_id进行关联,其中A->B是一对多且双向绑定关系。对此关联关系保证可编辑和新增。整体思路:新增时候直接双向绑定,修改时候先根据id全部删除,再新增关联关系。特此设计整理如下:

一、表结构和实体类

1.equity_limit_buy_set

CREATE TABLE `equity_limit_buy_set` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `del_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '删除状态:0否,1是',
  `equity_id` bigint(20) NOT NULL COMMENT '权益id',
  `effective_days` tinyint(1) NOT NULL DEFAULT '0' COMMENT '自购买后有效天数:默认值0:无限制',
  `limit_buy_num_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '购买次数类型限制:0不限购,1终身限购,2按周期限购,默认值0',    
  `limit_buy_num_cycle` tinyint(1) NOT NULL DEFAULT '0' COMMENT '购买次数周期限制:0终生,1每天,2每周,3每月',
  `limit_buy_num` int(11) NOT NULL DEFAULT '-1' COMMENT '限购数量:默认值:-1不限购',
  `limit_buy_user` bit(1) NOT NULL DEFAULT b'0' COMMENT '人群标签ID,0不限制购买人群,1:限制',
  `mutex_equity` bit(1) NOT NULL DEFAULT b'0' COMMENT '互斥权益ID列表,默认值:0没有互斥权益,1:有互斥权益',
  `stock_num` int(11) NOT NULL DEFAULT '-1' COMMENT '库存数量',
  `buy_button_text` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '立即购买' COMMENT '权益详情页:按钮文本',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_equity_id` (`equity_id`)
) COMMENT='权益限购设置';

在这里插入图片描述

2.equity_limit_buy_mutex_equity

CREATE TABLE `equity_limit_buy_mutex_equity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `del_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '删除状态:0否,1是',
  `equity_id` bigint(20) NOT NULL COMMENT '权益id',
  `mutex_equity_id` bigint(20) NOT NULL COMMENT '互斥权益id',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_equity_id` (`equity_id`),
  KEY `idx_mutex_equity_id` (`mutex_equity_id`)
) COMMENT='互斥权益关联设置';

在这里插入图片描述
其中equity_limit_buy_set中如果没有mutex_equity互斥权益,则mutex_equity为0;如果有则为1。然后在equity_limit_buy_mutex_equity中维护equity_id和mutex_equity_id的双向绑定关联关系。

3.EquityLimitBuySetConstant常量枚举类

public class EquityLimitBuySetConstant {

    /**
     * 购买次数限制:0不限购,1终身限购,2按周期限购,默认值0
     */
    @Getter
    @AllArgsConstructor
    public enum limitBuyNumTypeEnum{
        no_purchase_restrictions(0,"不限购"),
        lifetime_limit(1,"终身限购"),
        restricted_by_cycle(2,"按周期限购");

        private int code;
        private String message;
    }

    /**
     *购买次数限制:0终生,1每天,2每周,3每月
     */
    @Getter
    @AllArgsConstructor
    public enum limitBuyNumCycleEnum{
        lifetime(0,"终生") {
            @Override
            public Date[] getIntervalTime() {
                return null;
            }
        },
        daily(1,"每天") {
            @Override
            public Date[] getIntervalTime() {
                return new Date[]{DateUtils.getStartOfDay(new Date()),DateUtils.getEndOfDay(new Date())};
            }
        },
        weekly(2,"每周") {
            @Override
            public Date[] getIntervalTime() {
                return DateUtils.getWeekStartAndEnd(0);
            }
        },
        monthly(3,"每月") {
            @Override
            public Date[] getIntervalTime() {
                return DateUtils.getMonthStartAndEnd();
            }
        };
        private int code;
        private String message;

        protected abstract Date[] getIntervalTime();

        public static Date[] getDateArray(int code){
            final limitBuyNumCycleEnum cycleEnum = Arrays.stream(values()).filter(v -> v.code == code).findFirst().orElse(null);
            if(Objects.isNull(cycleEnum)){
                return null;
            }
            return cycleEnum.getIntervalTime();
        }
    }

4.请求和响应体EquityInfoEditReq

@Data
public class EquityInfoEditReq {

    @ApiModelProperty("权益基本信息")
    @NotNull(message = "权益基本信息不能为空")
    private EquityInfo baseInfo;

    @ApiModelProperty("权益附加信息")
    private EquityInfoExt extInfo;

    @ApiModelProperty("权益限购设置")
    private EquityLimitBuySetReq equityLimitBuySetReq;
}    

EquityLimitBuySetReq

@Data
public class EquityLimitBuySetReq{

    @ApiModelProperty("权益id")
    private Long equityId;

    @ApiModelProperty("自购买后有效天数:默认值0:无限制,其他值为实际有效天数")
    private Integer effectiveDays;

    @ApiModelProperty("购买次数限制:0不限购,1终身限购,2按周期限购,默认值0")
    private Integer limitBuyNumType;

    @ApiModelProperty("购买周期限制:0终生,1每天,2每周,3每月,默认值0")
    private Integer limitBuyNumCycle;

    @ApiModelProperty("限购数量:默认值:-1不限购,其他值为实际限购数量")
    private Integer limitBuyNum;

    @ApiModelProperty("限购人群设置:默认0不限制购买人群,1:限制;实际限购人群配置在limitBuyUserGroup")
    private Byte limitBuyUser;

    @ApiModelProperty("互斥权益设置:默认值0没有互斥权益,1:有互斥权益;实际互斥权益配置在mutexEquityIds")
    private Byte mutexEquity;

    @ApiModelProperty("库存数量:默认-1不限制,其他值为实际库存数量")
    private Integer stockNum;

    @ApiModelProperty("限购人群组列表")
    private List<Long> limitBuyUserGroup;

    @ApiModelProperty("互斥权益列表")
    private List<Long> mutexEquityIds;

    @ApiModelProperty(value = "权益详情页:购买按钮文本")
    private String buyButtonText;
}

二、业务逻辑层,主要涉及缓存的处理

1.EquityLimitBuySetService

public interface EquityLimitBuySetService extends IService<EquityLimitBuySet> {

    /**
     * 获取权益限购设置
     * @param limitBuySetByEquityId
     * @return EquityLimitBuySet
     */
    EquityLimitBuySet getLimitBuySetByEquityId(Long limitBuySetByEquityId);

    /**
     * 移除权益限购设置
     * @param equityId
     * @return boolean
    */
    boolean removeByEquityId(Long equityId);

    /**
     * 获取权益购买限制配置
     * @param id
     * @return
     * @throws Exception
     */
    EquityLimitBuySetReq getLimitBuySet(Long id) throws Exception;
}

2.EquityLimitBuySetServiceImpl

@Service
public class EquityLimitBuySetServiceImpl extends ServiceImpl<EquityLimitBuySetMapper, EquityLimitBuySet>
    implements EquityLimitBuySetService{

    @Autowired
    private EquityLimitBuyUserService equityLimitBuyUserService;

    @Autowired
    private EquityLimitBuyMutexEquityService equityLimitBuyMutexEquityService;

    private static final String BUY_SET = "buySet";

     /**
     * 获取权益限购设置
     * @param equityId
     * @return EquityLimitBuySet
     */
    @Override
    @Cacheable(value = BUY_SET,key = "#p0")
    public EquityLimitBuySet getLimitBuySetByEquityId(Long equityId) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("equity_id",equityId);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * 移除权益限购设置
     * @param equityId
     * @return boolean
     */
    @CacheEvict(value=BUY_SET,key="#p0")
    @Override
    public boolean removeByEquityId(Long equityId) {
         return lambdaUpdate()
                .eq(EquityLimitBuySet::getEquityId, equityId)
                .remove();
    }
    
    /**
     * 获取权益购买限制配置
     * @param id
     * @return
     * @throws Exception
     */
    @Override
    public EquityLimitBuySetReq getLimitBuySet(Long id) throws Exception {
        EquityLimitBuySet equityLimitBuySet = this.getLimitBuySetByEquityId(id);
        if (equityLimitBuySet != null) {
            EquityLimitBuySetReq equityLimitBuySetReq = BeanCopyUtils.copyProperties(EquityLimitBuySetReq.class, equityLimitBuySet);
            if(equityLimitBuySet.getMutexEquity()){
                equityLimitBuySetReq.setMutexEquityIds(equityLimitBuyMutexEquityService.getMutexEquity(id));
            }
            if(equityLimitBuySet.getLimitBuyUser()){
                equityLimitBuySetReq.setLimitBuyUserGroup(equityLimitBuyUserService.getEquityLimitBuyUserByEquityId(id));
            }
            return equityLimitBuySetReq;
        }
        return null;
    }

    /**
     * 重写saveOrUpdate方法,清空缓存
     * */
    @CacheEvict(value=BUY_SET,key="#p0.equityId")
    @Override
    public boolean saveOrUpdate(EquityLimitBuySet entity) {
        return super.saveOrUpdate(entity);
    }
}

3.EquityLimitBuyMutexEquityService

public interface EquityLimitBuyMutexEquityService extends IService<EquityLimitBuyMutexEquity> {
    /**
     * 查找互斥权益
     * @param limitBuyMutexByEquityId
     * @return
     */
    List<Long> getMutexEquity(Long limitBuyMutexByEquityId);

    /**
     * 保存权益和互斥权益关联关系
     * @param equityId
     * @param mutexEquityIds
     */
    void saveOrUpdateLimitBuyMutex(Long equityId, List<Long> mutexEquityIds);

    /**
     * 移除互斥权益关联设置关系
     * @param equityId
     * @return
     */
    boolean removeByEquityId(Long equityId);
}

4.EquityLimitBuyMutexEquityServiceImpl

@Service
public class EquityLimitBuyMutexEquityServiceImpl extends ServiceImpl<EquityLimitBuyMutexEquityMapper, EquityLimitBuyMutexEquity>
    implements EquityLimitBuyMutexEquityService{

    private final static String BUY_MUTEX_EQUITY = "buyMutexEquity";

    /**
     * 查找互斥权益
     * @param limitBuyMutexByEquityId
     * @return
     */
    @Override
    @Cacheable(value = BUY_MUTEX_EQUITY,key = "#p0")
    public List<Long> getMutexEquity(Long limitBuyMutexByEquityId) {
        final List<EquityLimitBuyMutexEquity> equities = lambdaQuery().eq(EquityLimitBuyMutexEquity::getEquityId, limitBuyMutexByEquityId)
                .select(EquityLimitBuyMutexEquity::getMutexEquityId)
                .list();
        return equities.stream().map(EquityLimitBuyMutexEquity::getMutexEquityId).collect(Collectors.toList());
    }

    /**
     * 保存权益和互斥权益关联关系
     * @param equityId
     * @param mutexEquityIds
     */
    @CacheEvict(value = BUY_MUTEX_EQUITY,key="#p0")
    @Override
    public void saveOrUpdateLimitBuyMutex(Long equityId, List<Long> mutexEquityIds) {
        List<EquityLimitBuyMutexEquity> buyMutexEquity = new ArrayList<>();

        //删除双向绑定的互斥关系,采用nonIn是增量更新删除,提升效率
        lambdaUpdate()
                .notIn(EquityLimitBuyMutexEquity::getMutexEquityId,mutexEquityIds)
                .eq(EquityLimitBuyMutexEquity::getEquityId,equityId)
                .remove();
        lambdaUpdate()
                .notIn(EquityLimitBuyMutexEquity::getEquityId,mutexEquityIds)
                .eq(EquityLimitBuyMutexEquity::getMutexEquityId,equityId)
                .remove();

        //查找双向绑定的互斥关系
        List<EquityLimitBuyMutexEquity> mutexIdsList = lambdaQuery()
                .in(EquityLimitBuyMutexEquity::getMutexEquityId, mutexEquityIds)
                .eq(EquityLimitBuyMutexEquity::getEquityId,equityId)
                .list();
        List<EquityLimitBuyMutexEquity> equityIdsList = lambdaQuery()
                .eq(EquityLimitBuyMutexEquity::getMutexEquityId, equityId)
                .in(EquityLimitBuyMutexEquity::getEquityId,mutexEquityIds)
                .list();

        //获取双向绑定的互斥权益id和权益id
        Set<Long> mutexIds = mutexIdsList.stream().map(EquityLimitBuyMutexEquity::getMutexEquityId).collect(Collectors.toSet());
        Set<Long> equityIds = equityIdsList.stream().map(EquityLimitBuyMutexEquity::getEquityId).collect(Collectors.toSet());

        //保存双向绑定的关联关系
        mutexEquityIds.stream().forEach(
                i -> {
                    if(!mutexIds.contains(i)){
                        EquityLimitBuyMutexEquity mutexIdEquity = EquityLimitBuyMutexEquity.builder()
                                .equityId(equityId)
                                .mutexEquityId(i)
                                .build();
                        buyMutexEquity.add(mutexIdEquity);
                    }

                    if(!equityIds.contains(i)){
                        EquityLimitBuyMutexEquity equityIdEquity = EquityLimitBuyMutexEquity.builder()
                                .equityId(i)
                                .mutexEquityId(equityId)
                                .build();
                        buyMutexEquity.add(equityIdEquity);
                    }
                });
        this.saveBatch(buyMutexEquity);
    }

    /**
     * 移除互斥权益关联设置关系
     * @param equityId
     * @return
     */
    @CacheEvict(value = BUY_MUTEX_EQUITY,key="#p0")
    @Override
    public boolean removeByEquityId(Long equityId) {
        return lambdaUpdate()
                .eq(EquityLimitBuyMutexEquity::getEquityId,equityId)
                .remove();
    }
}

5.saveOrUpdateEquityLimitBuySet

    /**
     * 保存或修改权益限购设置
     *
     * @param equityId
     * @param req
     * @return Long
     * @throws CommonException
     */
    public Boolean saveOrUpdateEquityLimitBuySet(Long equityId, EquityInfoEditReq req) throws Exception {
        EquityLimitBuySetReq buySetReq = req.getEquityLimitBuySetReq();
        if (buySetReq != null) {
            EquityLimitBuySet equityLimitBuySet = BeanCopyUtils.copyProperties(EquityLimitBuySet.class, buySetReq);
            equityLimitBuySet.setDelFlag(false);
            equityLimitBuySet.setEquityId(equityId);
            EquityLimitBuySet limitBuySetByEquityId = equityLimitBuySetService.getLimitBuySetByEquityId(equityId);
            if(limitBuySetByEquityId != null){
			    //后续用于保存或者新增判断标志
                equityLimitBuySet.setId(limitBuySetByEquityId.getId());
            }
            //互斥权益id列表
            List<Long> mutexEquityIds = buySetReq.getMutexEquityIds();

            //保存或修改互斥权益id列表
            if (CollectionUtils.isEmpty(buySetReq.getMutexEquityIds())) {
                equityLimitBuySet.setMutexEquity(false);
				//删除缓存
                equityLimitBuyMutexEquityService.removeByEquityId(equityId);
            } else {
                equityLimitBuySet.setMutexEquity(true);
                equityLimitBuyMutexEquityService.saveOrUpdateLimitBuyMutex(equityId, mutexEquityIds);
            }
            equityLimitBuySetService.saveOrUpdate(equityLimitBuySet);
        }else{
            //权益限购设置为空的时候移除缓存
            equityLimitBuySetService.removeByEquityId(equityId);
            equityLimitBuyMutexEquityService.removeByEquityId(equityId);
        }
        return true;
    }

三、测试结果

在这里插入图片描述
在这里插入图片描述

四、总结

新增和删除关联关系表数据时候,需要考虑各种情况,尤其是对缓存淘汰时机的把控。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 基于springboot+springmvc+mybatis-plus的微信小程序美容预约平台源码(前后台).zip 简介 本小程序是一个在线的美容预约平台。其主要服务类型为:美甲,美容,美发,美睫。用户可以通过该平台进行相关服务的预约。 实现技术 # 简介 本项目是一个前后端分离的一个项目,前端是微信小程序语言,后端是java语言。 技术栈: 用到了spring boot技术栈。即springboot+springmvc+mybatis-plus为主要技术。Mybatis-plus可以在操作单时极大优化效率,无需写sql语句。 # 数据数据库的设计遵循了设计规范,第三范式,mybatis-plus数据时用到了关联查询。详细设计见数据。 # 前后端交互 前后端交互主要前端使用微信小程序中ajax请求,即wx.request以json格式向后台传递数据。后端接收后进行相应处理。 小程序功能 # 信息页 主要是根据服务类型进行服务项目的展示,用户点击服务项目可以查看项目详细信息,点击预定可以进行服务的预定。 # 订单页 订单页允许用户查看自己至今的订单列,点击订单可以查看订单详细信息。如果订单未过期允许取消订单。 # 我的页 允许用户登陆后查看自己的信息即钱包余额。点击修改资料即可跳转到资 修改页。 注意:小程序大部分页面会检查用户登陆状态,未登录提示用户登陆后操作!!! 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值