数据库主键生成策略:
- 自增长:
优点:有序容易实现,缺点:无法保证数据的安全性,容易泄密、攻击
- UUID:基于时间、机器等随机生成的字符串
优点:安全、保密,缺点:长度较长,随机生成的字符串无法保证有序
- 思路:
不论基于何种策略,查询的时候都是基于自然顺序即数据物理地址,而物理地址是有序的。问题在于插入的时候, 自增长策略保证了有序插入,而UUID是随机生成的字符串,按ASCII排序,后生成的字符串有可能排在前面,导致了查询的时候是无序的,没有先后顺序。如果把ID字符串拆分成两部分,第一部分用来排序,第二部分用来保证唯一性,则既保证了先后顺序,又保证了数据安全性。所以第一部分采用时间戳到秒(同一秒的数据也无所谓先后顺序),后一部分采用UUID,然后加密为MD5的16位,缩短长度。
ID生成工具类
package com.lezic.util;
import java.util.Date;
import java.util.UUID;
/**
* 主键ID生成工具
*
* @author lincl
*/
public class IdUtil {
/**
* 获取有序的UUID
*
* @return
*/
public static String sortUUID() {
String uuid = UUID.randomUUID().toString();
String md5 = EncryptUtil.shortMd5(uuid);
return DateUtil.format(new Date(), "yyyyMMddHHmmss") "_" md5;
}
public static void main(String[] args) throws InterruptedException {
System.out.println(IdUtil.sortUUID());
Thread.sleep(1000);
System.out.println(IdUtil.sortUUID());
Thread.sleep(1000);
System.out.println(IdUtil.sortUUID());
Thread.sleep(1000);
System.out.println(IdUtil.sortUUID());
Thread.sleep(1000);
System.out.println(IdUtil.sortUUID());
}
}
生成效果
基于mybatis-plus注册ID生成器,便于插入数据库的ID自动生成
package com.lezic.config;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.MybatisMapWrapperFactory;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@MapperScan({"com.lezic.modules.**.dao", "com.lezic.service.**.dao"})
public class MybatisPlusConfig {
@Bean
public IdentifierGenerator idGenerator() {
return new MybatisSortUUIDGenerator();
}
}
实体类定义
package com.lezic.modules.demo.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* Demo例子
*
* @author lincl
* @date 2020-07-09
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class DemoStudent extends Model<DemoStudent> {
private static final long serialVersionUID = 1L;
/**
* 学生ID
*/
@TableId(value = "demo_student_id", type = IdType.ASSIGN_UUID)
private String demoStudentId;
/**
* 学号
*/
private String studentNo;
// 其它字段定义
}