理论知识参考上篇文章: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>
对应的异步方法未进行真正的异步方法调用,只是进行方法调用说明,开启异步调用的注解,修改方法的访问权限 即可实现异步方法的调用,要稍微修改返回值的处理。也可以使用自定义异步线程池。