资料
单表
可以借助于mysql自带的id生成器每次自增+1的方式来生成主键id。
分库分表
需要提前在外部生成id,然后将记录插入到对应的分表中。
其实原理很简单,只需实现一个id批量生成查询器即可,大概步骤:
graph TD
A[消费端] -->|Get ID| B(缓存)
B --> C{判断是否超出范围}
C -->|没有超出| A[消费端]
C -->|超出范围| E[生产服务]
E -->F[数据库]
- 本地引入一个client二方包,当有记录要插入数据库表时,调用nextId方法生成一个id,由于是提前分配的,大多数情况下从本地cache取,如果分配完了,需要从服务器再次申请。
1 2 3 4
| private final ConcurrentHashMap<CacheKey, CachedRange> cache = new ConcurrentHashMap<CacheKey, CachedRange>();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public long nextId(String app, String key) { synchronized (this){ CacheKey cacheKey = new CacheKey(app, key); CachedRange cachedRange = this.cache.get(cacheKey); if (cachedRange == null || cachedRange.range.getEnd() < cachedRange.pos) { IDRange range = this.service.getNextRange(app, key, this.size); cachedRange = new CachedRange(range, range.getStart()) ; } long pos = cachedRange.pos; cachedRange.pos += 1; this.cache.put(cacheKey, cachedRange); return pos; } }
|
- 初始化时或者分配的区间段用完,此时需要从远程服务器申请
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public IDRange getNextRange(String app, String key, int size) { synchronized (this) { IDRange result = new IDRange(); IDRange range = this.getAndUpdate(app, key, size * this.PRE_ALOCATE_BATCH_NUM); result.setApp(app); result.setKey(key); result.setStart(range.getStart()); result.setEnd(range.getEnd());
this.logger.info("return range: {}", result); return result; } }
@Transactional(value="crtTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public IDRange getAndUpdate(String app, String key, int size) { Map<String, String> params = new HashMap<String, String>(); params.put("app", app); params.put("key", key); SqlSession sqlSession = this.commonSqlSessionTemplate.getSqlSessionFactory() .openSession(); UniversalId universalId = sqlSession.selectOne("select Update;", params); if (universalId == null) { return null; }
IDRange range = new IDRange(); range.setApp(app); range.setKey(key); range.setStart(universalId.getValue() + 1); range.setEnd(universalId.getValue() + size - 1);
universalId.setValue(universalId.getValue() + size); sqlSession.update("updateValue", universalId); return range; }
|