| 代码的实现稍微复杂一点,获取 ID 会根据业务标识 sequencename,先从内存获取 Step 的 ID 段,如果为  null,则从数据库中读取当前最新的值,并根据步长计算 Step,然后返回请求 ID。如果从内存中直接获取到 Step,则直接取 ID,并对  currentValue 进行加一。当 currentValue 的值超过 endValue 时,则更新数据库的 ID,重新计算 Step。 private Map<String,Step> stepMap = new HashMap<String, Step>();  public synchronized long get(String sequenceName) {  Step step = stepMap.get(sequenceName);  if(step ==null) {  step = new Step(startValue,startValue+blockSize);  stepMap.put(sequenceName, step);  } else { if (step.currentValue < step.endValue) {  return step.incrementAndGet();  } }  if (getNextBlock(sequenceName,step)) {  return step.incrementAndGet();  }  throw new RuntimeException("No more value.");  }  private boolean getNextBlock(String sequenceName, Step step) {  // "select id from sequence_value where name = ?";  Long value = getPersistenceValue(sequenceName);  if (value == null) { try {  // insert into sequence_value (id,name) values (?,?)  value = newPersistenceValue(sequenceName);  } catch (Exception e) {  value = getPersistenceValue(sequenceName);  }  }  // update sequence_value set id = ? where name = ? and id = ?  boolean b = saveValue(value,sequenceName) == 1;  if (b) {  step.setCurrentValue(value);  step.setEndValue(value+blockSize); }  return b;  } 
 使用该方法获取 ID 可以减少对数据库的访问量,以降低数据库的压力,但是同样需要注意,获取 ID  同样关注数据库事务问题,因为当系统重启的时候,stepMap 为 null,所以会取数据库查询当前 ID,更计算更新 Step,然后更新数据库的  ID。如果该方法被放到数据库事务里,由于其他方法性能慢了,导致查询之后没有及时更新,并发情况下另一个线程查询的时候,可能会获取到该线程未提交的  ID,因而出现两个线程获取到相同的 ID 问题。 本文小结 订单号生成是一个非常简单的功能,但是在高并发的场景下,高性能和高可用就成为了需要关注的要点。所以,实际工作中的每一个小细节都值得我们去深思。                          (编辑:宣城站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |