Leaf-segment 双buffer数据库方案-代码实现

理论知识参考上篇文章:https://blog.csdn.net/lzl907678041/article/details/121282237

controller层方法调用

 @GetMapping("/currentLongId")
    @ApiOperation(value = "单个DB信息-获取当前LongId",notes = "单个DB信息-获取当前LongId")
    public Result currentLongId(@RequestParam("businessTag") String businessTag){
        return ResultBuilder.success(segmentService.currentId(businessTag));
    }

service定义

package com.cus.web.service.inter;

import com.cus.web.entity.Segment;
import com.cus.web.param.response.LeafSegmentV;

import java.util.List;

/**
 * @author lzl
 * @date: 2021-11-10 17:05
 */
public interface SegmentService {

    /**
     * 根据业务标识获取记录
     * @param businessTag
     * @return
     */
    Segment findByBusinessTag(String businessTag);

    /**
     * 获取当前记录的id
     * @param businessTag
     * @return
     */
    long currentId(String businessTag);

    /**
     * 获取当前缓存中的缓存数据
     * @return
     */
    List<LeafSegmentV> cacheData();

}

impl的实现代码

package com.cus.web.service.impl;

import com.cus.web.entity.Segment;
import com.cus.web.mapper.second.SegmentMapper;
import com.cus.web.param.response.LeafSegmentV;
import com.cus.web.service.inter.SegmentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @author lzl
 * @date: 2021-11-10 17:06
 */
@Service
@RequiredArgsConstructor
public class SegmentServiceImpl implements SegmentService {

    private final SegmentMapper segmentMapper;

    private final ReentrantLock reentrantLock = new ReentrantLock(true);

    /**
     * 第一个缓存id的对象
     */
    private LeafSegmentV firstLeafSegmentV = new LeafSegmentV();

    /**
     * 第二个缓存id的对象
     */
    private LeafSegmentV secondLeafSegmentV = new LeafSegmentV();

    @Override
    public Segment findByBusinessTag(String businessTag) {
        return segmentMapper.findByBusinessTag(businessTag);
    }

    @Override
    public long currentId(String businessTag) {
        reentrantLock.lock();
        try {
            return getLongId(businessTag);
        }catch (Exception e){
            System.out.println("生成id异常");
        }finally {
            reentrantLock.unlock();
        }
        return 0;
    }

    /**
     *
     * @param businessTag
     * @return
     */
    private long getLongId(String businessTag){
        LeafSegmentV leafSegmentV = null;
        if(CollectionUtils.isEmpty(firstLeafSegmentV.getIndexList())
                && CollectionUtils.isEmpty(secondLeafSegmentV.getIndexList())){
            // 均不存在 从DB加载数据
            loadDbId(businessTag, firstLeafSegmentV);
            leafSegmentV = firstLeafSegmentV;
        }else {
            // 存在数据
            if(firstLeafSegmentV.getIndex() > 0 ){
                leafSegmentV = firstLeafSegmentV;
            }else {
                if(secondLeafSegmentV.getIndex() > 0 ){
                    leafSegmentV = secondLeafSegmentV;
                }
            }
        }
        if(null == leafSegmentV){
            throw new RuntimeException("id生成异常");
        }
        return getLongId(businessTag,leafSegmentV) ;
    }

    /**
     * 获取数组中的id值
     * @param businessTag
     * @param leafSegmentV 取id记录的数据
     * @return
     */
    private long getLongId(String businessTag,LeafSegmentV leafSegmentV){
        List<Long> indexList = leafSegmentV.getIndexList();
        int index = leafSegmentV.getIndex();
        long id = indexList.get(index);
        if(index == indexList.size() -1 ){
            clearData(leafSegmentV);
            return id;
        }
        if(index == leafSegmentV.getTriggerPoint()){
            // 另外一个容器中 异步加载数据
            asyncLoadDbId(businessTag,(firstLeafSegmentV == leafSegmentV) ? secondLeafSegmentV : firstLeafSegmentV);
        }
        leafSegmentV.setIndex(++index);
        return id;
    }

    /**
     * 同步加载数据-首次加载数据
     * 从DB中加载数据
     * @param businessTag
     * @param leafSegmentV
     */
    private void loadDbId(String businessTag,LeafSegmentV leafSegmentV){
        Segment segment = findByBusinessTag(businessTag);
        handleSegment(segment,leafSegmentV);
    }

    /**
     * 异步加载数据-非首次加载数据
     * @param businessTag
     * @param leafSegmentV
     */
    private void asyncLoadDbId(String businessTag,LeafSegmentV leafSegmentV){
        Segment segment = findByBusinessTag(businessTag);
        handleSegment(segment,leafSegmentV);
    }

    /**
     * 处理DB加载后的数据、进行处理数据
     * @param segment
     * @param leafSegmentV
     */
    private void handleSegment(Segment segment,LeafSegmentV leafSegmentV){
        Long maxId = segment.getMaxId();
        Integer step = segment.getStep();
        long initValue = maxId - step;
        List<Long> indexList = leafSegmentV.getIndexList();
        indexList.clear();
        for (int i = 0; i < step; i++) {
            indexList.add(initValue + i);
        }
        leafSegmentV.setTriggerPoint(step / 10);
        leafSegmentV.setIndex(1);
    }

    /**
     * 对取完id数据的对象进行初始化
     * @param leafSegmentV
     */
    private void clearData(LeafSegmentV leafSegmentV){
        leafSegmentV.setIndex(0);
        leafSegmentV.getIndexList().clear();
        leafSegmentV.setTriggerPoint(0);
    }

    @Override
    public List<LeafSegmentV> cacheData() {
        return Arrays.asList(firstLeafSegmentV,secondLeafSegmentV);
    }
}
LeafSegmentV 对象的定义代码
package com.cus.web.param.response;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author lzl
 * @date: 2021-11-11 09:15
 */
@Data
public class LeafSegmentV {

    /**
     * 当前数组取到的下标位置
     */
    private int index;

    /**
     * 存储id数据的集合
     * 默认当前集合无值
     */
    private List<Long> indexList = new ArrayList<>();

    /**
     * 触发加载数据的触发点
     */
    private int triggerPoint;

}
SegmentMapper接口定义
package com.cus.web.mapper.second;

import com.cus.web.entity.Segment;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface SegmentMapper {
    int deleteByPrimaryKey(String businessTag);

    int insert(Segment record);

    Segment selectByPrimaryKey(String businessTag);

    List<Segment> selectAll();

    int updateByPrimaryKey(Segment record);

    /**
     * 根据业务标识获取记录
     * @param businessTag
     * @return
     */
    Segment findByBusinessTag(@Param("businessTag") String businessTag);

}

SegmentMapper对应的xml实现

<mapper namespace="com.cus.web.mapper.second.SegmentMapper">
  <resultMap id="BaseResultMap" type="com.cus.web.entity.Segment">
    <id column="business_tag" jdbcType="VARCHAR" property="businessTag" />
    <result column="max_id" jdbcType="BIGINT" property="maxId" />
    <result column="step" jdbcType="INTEGER" property="step" />
    <result column="desc" jdbcType="VARCHAR" property="desc" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
  </resultMap>


<select id="findByBusinessTag" resultMap="BaseResultMap">
    begin;
    UPDATE segment SET max_id = max_id + step WHERE business_tag = #{businessTag};
    SELECT business_tag, max_id, step FROM segment WHERE business_tag = #{businessTag};
    commit;
  </select>

</mapper>

对应的异步方法未进行真正的异步方法调用,只是进行方法调用说明,开启异步调用的注解,修改方法的访问权限 即可实现异步方法的调用,要稍微修改返回值的处理。也可以使用自定义异步线程池。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值