MyBatis-Plus自定义ID生成策略

MyBatis-Plus是一个基于MyBatis的增强工具,提供了许多方便的功能,其中包括自动生成主键ID。虽然MyBatis-Plus默认提供了多种ID生成策略,但在某些特定场景下,我们可能需要自定义ID生成策略。本文将详细介绍如何在MyBatis-Plus中实现自定义ID生成策略。

一、为什么需要自定义ID生成策略?

在某些情况下,业务需求可能要求我们使用特定的ID生成规则,例如:

  • 分布式系统中的全局唯一ID
  • 高并发下的高性能ID生成
  • 符合特定业务逻辑的ID格式

为了满足这些需求,我们可以通过自定义ID生成策略来实现。

二、自定义ID生成策略的实现步骤

1. 引入必要依赖

在 pom.xml中添加MyBatis-Plus依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>
2. 实现自定义ID生成器

自定义ID生成器需要实现MyBatis-Plus提供的 IdentifierGenerator接口。以下是一个示例实现,基于雪花算法生成ID:

package com.example.demo.config;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Component
public class CustomIdGenerator implements IdentifierGenerator {

    private final long workerId;
    private final long datacenterId;

    public CustomIdGenerator() {
        this.workerId = getWorkerId();
        this.datacenterId = getDatacenterId();
    }

    @Override
    public Long nextId(Object entity) {
        return SnowflakeIdUtils.nextId(workerId, datacenterId);
    }

    private long getWorkerId() {
        // 根据实际需求实现获取workerId的逻辑
        return 1L;
    }

    private long getDatacenterId() {
        // 根据实际需求实现获取datacenterId的逻辑
        return 1L;
    }
}
3. 实现雪花算法

雪花算法是一种高效的分布式ID生成算法,能够保证ID的全局唯一性。以下是一个基于雪花算法的ID生成工具类:

package com.example.demo.config;

public class SnowflakeIdUtils {

    private static final long TWEPOCH = 1288834974657L;
    private static final long WORKER_ID_BITS = 5L;
    private static final long DATACENTER_ID_BITS = 5L;
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
    private static final long SEQUENCE_BITS = 12L;
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
    private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    private long lastTimestamp = -1L;
    private long sequence = 0L;

    public static synchronized long nextId(long workerId, long datacenterId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", MAX_WORKER_ID));
        }
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATACENTER_ID));
        }

        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) |
                (datacenterId << DATACENTER_ID_SHIFT) |
                (workerId << WORKER_ID_SHIFT) |
                sequence;
    }

    private static long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private static long timeGen() {
        return System.currentTimeMillis();
    }
}
4. 配置MyBatis-Plus使用自定义ID生成器

在Spring Boot配置类中注册自定义ID生成器:

package com.example.demo.config;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setIdentifierGenerator(new CustomIdGenerator());
        return globalConfig;
    }
}

三、应用自定义ID生成策略

在实体类上配置主键生成策略,使用自定义ID生成器:

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.IdType;
import lombok.Data;

@Data
public class User {

    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private String email;
}

四、验证自定义ID生成策略

编写测试代码,验证自定义ID生成策略是否生效:

package com.example.demo;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class CustomIdGeneratorTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsertUser() {
        User user = new User();
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");
        userMapper.insert(user);
        System.out.println("Inserted user ID: " + user.getId());
    }
}

分析说明表

步骤 说明 示例
引入必要依赖 在 pom.xml中添加MyBatis-Plus依赖 <dependency>...</dependency>
实现自定义ID生成器 实现 IdentifierGenerator接口,自定义ID生成逻辑 CustomIdGenerator
实现雪花算法 编写基于雪花算法的ID生成工具类 SnowflakeIdUtils
配置MyBatis-Plus 在Spring配置类中注册自定义ID生成器 MyBatisPlusConfig
应用自定义ID生成策略 在实体类上配置主键生成策略 User
验证自定义ID生成 编写测试代码,验证自定义ID生成策略 CustomIdGeneratorTest

总结

通过上述步骤,我们详细介绍了如何在MyBatis-Plus中实现自定义ID生成策略。自定义ID生成器能够满足特定业务需求,确保ID的全局唯一性和高效生成。希望本文能够为您在使用MyBatis-Plus时提供实用的参考,帮助您实现更加灵活和高效的ID生成策略。