模仿美团的leaf算法实现的,简易版本
基本思想:利用MySQL字段实现自增id,如果每次都去MySQL取id,性能较差,因此每次取id时,获取一个号段,比如一次获取2000个id,缓存在应用里,每次用完后再去MySQL数据库获取新的号段。
知识点:怎么在静态方法中调用非静态属性、怎么将两条sql放在一个事务里面
- 新建表,初始化数据(此处跟leaf算法相同)
CREATE TABLE `leaf_alloc` (
`biz_tag` varchar(128) NOT NULL DEFAULT '',
`max_id` bigint(20) NOT NULL DEFAULT '1',
`step` int(11) NOT NULL,
`description` varchar(256) DEFAULT NULL,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB;
insert into leaf_alloc(biz_tag, max_id, step, description) values('leaf-segment-test', 1686672000000, 2000, 'Test leaf Segment Mode Get Id')
- id生成器实现类
package com.xys.util;
import com.xys.entity.LeafAlloc;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class IDGen {
private static final Logger LOG = LoggerFactory.getLogger(IDGen.class);
private static final AtomicLong value = new AtomicLong(0);
private static volatile long max;
private static volatile int step;
private static final String BIZ_TAG = "leaf-segment-test";
@Resource
private SqlSessionFactory sqlSessionFactory;
//此处的idGen对象是为了在静态方法中调用非静态属性sqlSessionFactory
private static IDGen idGen;
@PostConstruct
public void init() throws Exception {
idGen = this;
idGen.sqlSessionFactory = this.sqlSessionFactory;
updateMaxIdAndGetLeafAlloc();
}
public static synchronized long nextId() {
long l = value.incrementAndGet();
if (l >= max) {
updateMaxIdAndGetLeafAlloc();
}
return l;
}
private static void updateMaxIdAndGetLeafAlloc() {
//更新和查询两条sql放在同一个事务里,目的是当成一次原子操作
try (SqlSession sqlSession = idGen.sqlSessionFactory.openSession(false)) {
//此处是mapper的全类名
sqlSession.update("com.xys.mapper.LeafAllocMapper.updateMaxId", BIZ_TAG);
LeafAlloc newAlloc = sqlSession.selectOne("com.xys.mapper.LeafAllocMapper.selectByPrimaryKey", BIZ_TAG);
sqlSession.commit();
value.set(newAlloc.getMaxId() - newAlloc.getStep());
max = newAlloc.getMaxId();
step = newAlloc.getStep();
LOG.info("更新数据库到id生成器,value:{}, max:{}, step:{}", value, max, step);
}
}
}
- mapper的updateMaxId sql
<update id="updateMaxId">
update leaf_alloc
set max_id = max_id + step
where biz_tag = #{bizTag,jdbcType=VARCHAR}
</update>