Segment Mode ID Generation: Advantages, Disadvantages, Application Scenarios, and Java Implementation
This article explains the segment‑mode ID generation strategy, analyzes its pros and cons, describes suitable application scenarios, and provides a complete Java implementation with database schema, supporting classes, and a multithreaded test case for high‑concurrency environments.
Segment mode is a common ID generation strategy used in high‑concurrency scenarios. The ID service fetches a batch of IDs from the database, caches them locally, and serves requests from the cache, reducing database load.
1. Advantages
Reduces database access pressure, improving system performance.
Improves availability and reliability; the service can continue operating during short‑term DB failures.
Strong scalability; easy to extend to multiple tables or shards for growing business needs.
Flexible adjustment of segment size or count to match changing requirements.
2. Disadvantages
Depends on the database; DB performance and stability directly affect ID service availability.
Generated IDs are pure numbers without business meaning, which may reduce readability for some use cases.
3. Application Scenarios
Segment mode suits medium‑concurrency situations where introducing extra middleware (e.g., Redis) is unnecessary, such as generating order numbers or payment transaction IDs that require efficient, stable creation.
4. Database Design
Create a code_seq table to store segment information:
drop TABLE IF EXISTS `code_seq`;
create TABLE `code_seq` (
`env` VARCHAR(10) NOT NULL COMMENT 'environment identifier',
`prefix` INT(10) NOT NULL COMMENT 'code prefix',
`seq` INT(10) NOT NULL COMMENT 'current sequence',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'last update time',
PRIMARY KEY(`prefix`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'CODE number table';Insert initial data for each environment (e.g., T1) with different prefixes:
INSERT INTO code_seq (env, prefix, seq) VALUES
('T1', 1001, 0),
('T1', 1002, 0),
('T1', 1003, 0),
('T1', 1004, 0),
('T1', 1005, 0),
('T1', 1006, 0),
('T1', 1007, 0),
('T1', 1008, 0),
('T1', 1009, 0),
('T1', 1010, 0);5. Code Design
The core classes are illustrated in the UML diagram (omitted here). Key components:
CodeHandler : Main class providing initialization and getCode() method, using atomic structures and a background loader to keep the cache filled.
CodeSegment : Encapsulates a segment, generates the next ID, and reports remaining IDs.
CodeTpsMonitor : Monitors request TPS and dynamically adjusts the batch size.
CodeSeqService : Interacts with the database to fetch and update sequences.
CodeSeqMapper : MyBatis mapper with SQL for selecting prefixes, fetching a row with lock, and updating the sequence.
public class CodeHandler {
private static final double UPDATE_THRESHOLD = 0.9f;
private final String name;
private final Set
codePrefixSet = new ConcurrentSkipListSet<>();
private final BlockingQueue
codeSegmentBlockingQueue = new LinkedBlockingQueue<>(1);
private final AtomicBoolean needLoading = new AtomicBoolean(false);
private final AtomicBoolean statusHealthy = new AtomicBoolean(false);
private final String idc = "T1";
private CodeSeqService codeSeqService;
private CodeTpsMonitor codeTpsMonitor;
private Executor loadingExecutor;
// constructor, setters, init, loadQueue, loadCodeAlloc, loadCodePrefix, getCode, inner CodeLoader ...
} public class CodeSegment {
private final int prefix;
private final int maxSeq;
private final AtomicLong curSequence;
public CodeSegment(int prefix, int maxSeq, long start) { ... }
public String getCode() { ... }
public long getIdle() { return maxSeq - curSequence.get() + 1; }
} public class CodeTpsMonitor implements Runnable {
public static final int INITIAL_BATCH_COUNT = 100;
private static final int MAX_BATCH_COUNT = 1000;
private final AtomicInteger step = new AtomicInteger(INITIAL_BATCH_COUNT);
private final String name;
private final AtomicInteger count = new AtomicInteger(0);
private long startTime;
private ScheduledExecutorService scheduledExecutorService;
// constructor, start, increase, getStep, run (calculates TPS and adjusts step) ...
}6. Test Case
A multithreaded JUnit test creates a CodeHandler , initializes it, and launches five threads each generating 200 codes, verifying the system works under concurrent load.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class CodeTest {
@Autowired
private CodeSeqService codeSeqService;
@Test
public void createCodeTestCase01() {
CodeHandler codeHandler = new CodeHandler("code-create");
codeHandler.setCodeSeqService(codeSeqService);
codeHandler.init();
// thread pool, CountDownLatch, CreateCodeJob submissions ...
}
// inner CreateCodeJob implements Runnable ...
}The article concludes with references to related posts about distributed ID generation and invites readers to follow the author for more technical sharing.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.