美团Leaf-Segment 生成ID使用说明
最近在搭建分布式项目时需要考虑全局ID的唯一性,经过对比百度、滴滴、美团开源的ID生成系统,最终选择了美团。然后根据自身项目情况稍微进行了一点修改,读者可根据下面的操作步骤进行配置后可直接使用。在本代码中不包含雪花算法生成ID的相关代码,如需了解可查看原开源地址 。
第一步
代码下载地址
第二步
pom中引入maven配置
<!--美团ID生产系统-->
<dependency>
<groupId>com.sankuai.inf.leaf</groupId>
<artifactId>leaf-core</artifactId>
<version>1.0.1-RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
第三步
启动类中加入@EnableLeafServer注解启用ID服务
@SpringBootApplication
@EnableLeafServer // ID 服务注解
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
第四步
application.yml配置文件加入如下配置
leaf:
segment:
url: jdbc:mysql://127.0.0.1:3306/leaf?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&nullCatalogMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
username: root
name: test #默认为leaf-id
第五步
在第四步使用的数据库中创建数据表
CREATE TABLE `leaf_alloc` (
`biz_tag` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'ID标签,如活动模块则可设置标签为activity' ,
`max_id` bigint(20) NOT NULL DEFAULT 1 COMMENT '当前最大ID值' ,
`step` int(11) NOT NULL COMMENT '步长,每一次请求获取的ID个数' ,
`description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '说明' ,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ,
PRIMARY KEY (`biz_tag`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='ID管理数据表'
ROW_FORMAT=DYNAMIC;
要生成不同模块的ID只需要在该数据表中插入插入一条数据即可。例如要生成活动的ID,则执行如下insert语句:
# biz_tag 为ID标签可随意定义,确保唯一性即可
# max_id 当前最大ID值,如果是原来已经是自增ID且ID已经达到某值(如:92),则这里max_id可以设置为93。
# step 每次请求获取的ID个数,当系统用完缓存中的ID后会再创请求获取ID号段并更新max_id值
# description 备注说明,注明当前行是哪个模块的ID
INSERT INTO `leaf_alloc` (`biz_tag`, `max_id`, `step`, `description`) VALUES ('activity', '1', '10000', '说明的信息ID');
第六步
创建自定义ID生成策略类,注:该策略只适用于JPA或Hibernate框架
import com.sankuai.inf.leaf.SegmentServiceUtil;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import java.io.Serializable;
import java.util.Properties;
/**
* 生成自定义ID策略,这里通过使用引用美团ID生成ID进行处理
* @author lizebin
* @version 1.0
* @date 2021/2/19 9:34 下午
*
**/
public class CustomIDGenerator implements IdentifierGenerator, Configurable {
/**对应ID管理表中biz-tag字段的值*/
private String bizTag;
@Override
public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object o) throws HibernateException {
return SegmentServiceUtil.getId(this.bizTag);
}
@Override
public boolean supportsJdbcBatchInserts() {
return true;
}
@Override
public void configure(Type type, Properties properties, ServiceRegistry serviceRegistry) throws MappingException {
this.bizTag = properties.getProperty("biz-tag");
}
}
第六步
实体类中使用CustomIDGenerator策略生成ID,在主键字段中增加 @GeneratedValue @GenericGenerator两个注解,配置如下代码所示。需要注意GeneratedValue
中generator
属性的值必须与GenericGenerator
中name
属性的值一致。
GenericGenerator
中的strategy
属性值为CustomIDGenerator
类的路径名称(含包路径)
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-id")
@GenericGenerator(name = "custom-id", strategy = "com.test.CustomIDGenerator", parameters = { @org.hibernate.annotations.Parameter(name = "biz-tag", value = "activity")})
@Column(name = "id", length = 20)
private Long id;
补充说明
如果不想通过第六步方式进行ID的设置可以用以下方式获取ID的值
// 方式一,调用工具类传入ID标签获取ID
SegmentServiceUtil.getId(String bizTag);
// 方式二,注入SegmentService类传入ID标签获取ID
@Autowired
private SegmentService segmentService;
segmentService.getId("bizTag").getId();