在Java编程中,获取唯一不重复的编号是一个常见的需求,无论是在生成订单号、用户ID还是其他场景中。以下是一些常用的方法,以及如何在实际项目中应用这些方法。
1. 使用UUID
UUID(通用唯一识别码)是Java提供的一种生成唯一标识符的方式。UUID是128位的,几乎可以保证全局唯一。
import java.util.UUID;
public class UniqueIdGenerator {
public static String generateUUID() {
return UUID.randomUUID().toString();
}
public static void main(String[] args) {
String uniqueId = generateUUID();
System.out.println("生成的UUID: " + uniqueId);
}
}
2. 使用数据库自增主键
如果使用数据库,可以利用数据库自增主键的特性来获取唯一编号。以MySQL为例:
CREATE TABLE example (
id INT AUTO_INCREMENT PRIMARY KEY,
data VARCHAR(255)
);
在Java中,可以通过以下方式获取:
public class DatabaseIdGenerator {
public static int generateId() {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database", "username", "password");
statement = connection.prepareStatement("SELECT MAX(id) FROM example", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
resultSet = statement.executeQuery();
if (resultSet.last()) {
return resultSet.getInt("MAX(id)") + 1;
}
return 1;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0;
}
}
3. 使用雪花算法(Snowflake Algorithm)
雪花算法是一种基于时间戳的算法,能够生成一个64位的唯一ID,其中包括时间戳、数据中心ID、机器ID和序列号。
import java.util.concurrent.atomic.AtomicLong;
public class SnowflakeIdGenerator {
private final long twepoch = 1288834974657L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceBits = 12L;
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
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) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(0L, 0L);
for (int i = 0; i < 10; i++) {
System.out.println(idGenerator.nextId());
}
}
}
4. 使用Java的原子类AtomicLong
Java的AtomicLong类提供了线程安全的数值操作。可以通过AtomicLong来生成唯一编号。
import java.util.concurrent.atomic.AtomicLong;
public class AtomicLongIdGenerator {
private static final AtomicLong counter = new AtomicLong(0);
public static long generateId() {
return counter.incrementAndGet();
}
public static void main(String[] args) {
System.out.println("生成的ID: " + generateId());
}
}
实战技巧
- 在使用
UUID时,注意它的长度,可能会对数据库索引和存储造成影响。 - 使用雪花算法时,需要确保
workerId和datacenterId的唯一性,否则可能会生成重复的ID。 - 当使用数据库自增主键时,需要注意数据库的并发性能,特别是在高并发场景下。
- 使用
AtomicLong时,如果系统有多个实例,需要注意实例间的ID生成问题。
通过以上方法,你可以轻松地在Java中获取唯一不重复的编号。根据实际需求选择合适的方法,并注意相关技巧,可以帮助你更有效地进行开发。
