一:数据库自动生成:数据库,自增型主键。
插入操作完成后,返回主键值(以作他用),返回值写在传入参数的实体类中的主键属性中。另外,插入成功会返回1,代表受影响的记录条数(插入一条数据,受影响记录数自然为1)。
弊端:分库、分表,单一主键唯一性保证需要单独维护。
二:主键生成工具(工具类可以自定义)生成唯一不重复的主键。
好处:可以赋予业务含义、分库、分表都可以
比如:应用功能模块+时间戳+随机数
补充:雪花算法主键生成 Java代码:

/**
* 雪花算法-生成主键
* 基于Java long基本数据类型占内存64bit。
* 符号位(默认使用0):1bit
* 时间戳位(时间差):41bit
* 工作进程位:10bit
* 序列号位:12bit
*/
public class SnowflakeUtil {
/** 开始时间截 (2019-01-01) */
private final static long TWEPOCH = 1546272000000L;
/** 工作机器ID(0~(2^8)-1) */
private final static long WORKER_ID = getWorkerId();
/** 数据中心ID(0~(2^2)-1) */
private final static long DATA_CENTER_ID = getDataCenterId();
/** 机器id所占的位数 */
private final static long WORKER_ID_BITS = 8L;
/** 数据中心标识id所占的位数 */
private final static long DATA_CENTER_ID_BITS = 2L;
/** 支持的最大机器id,结果是(2^8)-1 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final static long MAX_WORKER_ID = -1L ^ (-1L << WORKER_ID_BITS);
/** 支持的最大数据中心标识id,结果是(2^2)-1 */
private final static long MAX_DATA_CENTER_ID = -1L ^ (-1L << DATA_CENTER_ID_BITS);
/** 序列在id中占的位数 */
private final static long SEQUENCE_BITS = 12L;
/** 机器ID向左移12位 */
private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
/** 数据中心标识id向左移17位(12+5) */
private final static long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
/** 时间截向左移22位(5+5+12) */
private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;
/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
private final static long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);
/** 毫秒内序列(0~4095) */
private static long sequence = 0L;
/** 上次生成ID的时间截 */
private static long lastTimestamp = -1L;
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
public static synchronized long nextId() {
if (WORKER_ID > MAX_WORKER_ID || WORKER_ID < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0", MAX_WORKER_ID));
}
if (DATA_CENTER_ID > MAX_DATA_CENTER_ID || DATA_CENTER_ID < 0) {
throw new IllegalArgumentException(
String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATA_CENTER_ID));
}
long timestamp = System.currentTimeMillis();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
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;
}
// 上次生成ID的时间截
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成64位的ID
return ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (DATA_CENTER_ID << DATA_CENTER_ID_SHIFT)
| (WORKER_ID << WORKER_ID_SHIFT) | sequence;
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
private static long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
/**
* 集群ID
*/
public static Long getWorkerId() {
return 1L;
}
/**
* 服务中心ID
*/
public static Long getDataCenterId() {
return 1L;
}
}
















