在集群的环境中,有这种场景
    需要整数自增ID,这个整数要求一直自增,并且需要保证唯一性.

Web服务器集群调用这个整数生成服务,然后根据各种规则,插入指定的数据库.
    
    一般来说,整数自增可以通过几个方式实现.
    1.MySQL 单独建一个表,使用Auto_increment特性.

  1. CREATE TABLE `test` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. PRIMARY KEY (`id`)
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8

如果需要生成ID,则Insert一个记录,然后获取last_insert_id()得到ID值

    
    这种方式的优点是简单,而且比较快.
    缺点是这个表会越来越大,需要定期进行清理.

2.Oracle 序列
    优点很明显,足够快,而且不占用空间.
    缺点..你需要有Oracle

3.mysql 单行更新自增

    需要生成ID的时候,进行如下调用

以上三种数据库方式的效率对比如下(都是测试的虚拟环境,作为趋势参考,数值是每秒生成的ID个数)

  单线程 5线程 10线程 20线程
MySQL Auto_increment 340-390 277 229 178
Oracle序列 714 555 454 454
MySQL 单行更新 303 136 66 19
 
 

4.使用Redis自增
    使用两个Redis实例,一个分发奇数ID,一个分发偶数ID
    任何一个Redis损坏,都可以切换到另外一个Redis实例.

5.使用程序模拟序列

下面的ID生成服务,初始化先从数据库拿到一段ID,然后分发。
    一旦ID耗尽,再从数据库获取一段ID。
    可以启动多个ID生成服务,避免单点故障.
    ID生成服务本身应该串行化,避免锁竞争.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class SeqGenerator {
private static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); private static int currentVal = -1;
private static int maxVal = -1;
private static int fetchSize = 10000;//每次生成一万个id static{
try {
fetchFromDB();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public static int getSeq() throws InterruptedException, ExecutionException {
Callable<Integer> c = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int result = currentVal;
if (currentVal > maxVal) {//如果当前值>数据库最大值,重新生成id
fetchFromDB();
result = currentVal;
}
currentVal++;
return result; }
};
Future<Integer> task = singleThreadExecutor.submit(c);
return task.get().intValue();
} private static void fetchFromDB() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "xx", "xx");
connection.setAutoCommit(false);
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("select * from test for update");
rs.next();
currentVal = rs.getInt(1) + 1;//当前值
rs.close();
st.executeUpdate("update test set id=id+" + fetchSize);//更新db中最大值
rs = st.executeQuery("select * from test for update");
rs.next();
maxVal = rs.getInt(1);//最大值
connection.commit();
rs.close();
st.close();
connection.close();
} public static void main(String[] args) throws Exception {
int i = 1000000;
long start = System.currentTimeMillis(); while (i > 0) {
System.out.println(SeqGenerator.getSeq());
i--;
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}

使用这种自定义序列,1百万ID的生成时间是14s.效果非常明显.

生成整数自增ID(集群主键生成服务)的更多相关文章

  1. Hibernate(4)——主键生成策略、CRUD 基础API区别的总结 和 注解的使用

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: hibernate的主键生成策略 UUID 配置的补充:hbm2ddl.auto属性用法 注解还是配置文件 h ...

  2. Hibernate主键生成策略及选择

    1 .increment:适用于short,int,long作为主键,不是使用数据库自动增长机制 这是hibernate中提供的一种增长机制 在程序运行时,先进行查询:select max(id) f ...

  3. [原创]java WEB学习笔记81:Hibernate学习之路--- 对象关系映射文件(.hbm.xml):hibernate-mapping 节点,class节点,id节点(主键生成策略),property节点,在hibernate 中 java类型 与sql类型之间的对应关系,Java 时间和日期类型的映射,Java 大对象类型 的 映射 (了解),映射组成关系

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. Hibernate学习笔记(三)Hibernate生成表单ID主键生成策略

    一. Xml方式 <id>标签必须配置在<class>标签内第一个位置.由一个字段构成主键,如果是复杂主键<composite-id>标签 被映射的类必须定义对应数 ...

  5. Centos7.6部署k8s v1.16.4高可用集群(主备模式)

    一.部署环境 主机列表: 主机名 Centos版本 ip docker version flannel version Keepalived version 主机配置 备注 master01 7.6. ...

  6. 4.ID主键生成策略

    保证唯一性(auto_increment) 一.xml方式 <?xml version="1.0"?> <!DOCTYPE hibernate-mapping P ...

  7. SpringJPA主键生成采用自定义ID,自定义ID采用年月日时间格式

    自定义主键生成策略 在entity类上添加注解 @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom ...

  8. EF中更新操作 ID自增但不是主键 ;根据ViewModel更新实体的部分属性

    //ID自增但不是主键的情况 public int Update_join<TEntity>(TEntity entity) where TEntity : class { dbconte ...

  9. mybatis plus 主键生成 Twitter雪花算法 id 及修改id为字符型

    mybatis plus配置主键生成策略为2,就是 使用Twitter雪花算法 生成id spring boot中配置为: GlobalConfiguration conf = new GlobalC ...

随机推荐

  1. template_1

    0: 模板是一些为多种类型而编写的函数和类,而且这些类型都没有指定.当使用模板的时候,只需要把所希望的类型作为一个(显示或隐示的)实参传递给模板.模板是语言本身所具有的特效,她完全支持类型检查和作用域 ...

  2. POJ 3928 Ping pong

    题目链接:http://poj.org/problem?id=3928 乒乓比赛,有N个人参加,输入每个玩家的技能等级,对每个人设置一个特定ID和一个技能值,一场比赛需要两个选手和一个裁判,只有当裁判 ...

  3. 【转载】分享下多年积累的对JAVA程序员成长之路的总结

    注:该文是从百度贴吧转载过来,之前看到觉得写得还不错,对Java开发学习者来说很有意义的,可以看看. 我也搞了几年JAVA了,由于一向懒惰,没有成为大牛,只是一普通程序猿,不爱玩社交网站,不爱玩微博, ...

  4. DTCMS视频模版更改,

    1.去掉style.css中视频的高度 .video-box{ position:relative; width:100%; height:473px; _clear:both; _display:i ...

  5. WeX5与阿里内测的Weex与有何纠葛?快来看HTML5开发圈那些逗逼事儿!

    4月21日~23日,由infoQ主办的2016 Qcon大会北京站如期举行. HTML5开发已经成为移动开发/前端专题中无可争议的焦点,核心议题已经由前几年的是否该用HTML5转向了如何高性能.高效率 ...

  6. js给数字加三位一逗号间隔的两种方法(面试题)

    方法一:   <script type= "text/javascript"> //保留三位小数,toLocaleString() 方法可把一个 Number 对象转换 ...

  7. 九度OJ做题记录 更新.....

    2015年1月7日 20:34:23  题目1007:奥运排序问题 有点意思,以后想另外方法快速做出来 2015年1月7日 21:03:56 有一个技巧就是,写了三个比较函数cmp1,cmp2,cmp ...

  8. PL/SQL数据导入导出浅谈(1)

    近来需要通过PL/SQL向Oracle中导数据,特此总结一下 试例表:test 字段:id;name;org; 1.直接复制粘贴(当数据量不是特别大的时候) 1)使用select * from tes ...

  9. 移动端webapp开发必备知识

    移动设备的用户越来越多,每天android手机的激活量都已经超过130万台,所以我们面向移动终端的WebAPP也开始跟进了.本文主要介绍webapp的开发与调试的相关知识和经验,以及给出几种可选的解决 ...

  10. EXTJS 4.2 资料 控件之tabpanel 静态生成tabpanel

    //**************页面主体开始***************** var tabpanel = Ext.createWidget('tabpanel', { activeTab: 0, ...