在集群的环境中,有这种场景
    需要整数自增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. L003-oldboy-mysql-dba-lesson03

          L003-oldboy-mysql-dba-lesson03 IOPS:每秒钟输入输出的数量 [root@web01 ~]# cat /proc/meminfo [root@web01 ~ ...

  2. 编译php5.6

    没想到编译个LAMP这么麻烦又简单. 按照官网的做就可以了,只是我在CentOs下一直会提示出现这个错误 按照官网的安装方法:install 用下面的参数: ./configure --with-ap ...

  3. 如何使用Git——(一)

    一.git与github git 是一款自由和开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目. github 是一个网站,给用户提供git仓库托管服务,是开源代码库以及版本控制系统.在 ...

  4. RequireJS入门与进阶

    RequireJS由James Burke创建,他也是AMD规范的创始人. RequireJS会让你以不同于往常的方式去写JavaScript.你将不再使用script标签在HTML中引入JS文件,以 ...

  5. HTML 中的字符集、ASCII、 ISO-8859-1、符号之间的关系和 HTML URL 编码注意的事项

    一.HTML 实体 1.什么是HTML 实体? 在 HTMl 中,某些字符是保留的.小于号 (<) 和 大于号 (>), 浏览器会误认为是标签 如果希望正确地显示预留字符,必须在 HTML ...

  6. 伪元素content的应用

    日常开发中,我们常用:before,:after来实现一些效果,比如 – 边框 – 图标 此时的content中只是为了伪元素能渲染出来而声明 1 2 3 div:before{ content: & ...

  7. 如何实现zs无限期试用

    要删除的文件有两个,分别是.zs与10_0..zs保存的是版本号,10_0保存的是注册码,这两个文件存在的原理是:zend studio 每次启动的会检查这两个文件的创建时间,和当前日期对比,超过30 ...

  8. C盘清理大作战

    C盘会随着使用时间慢慢变满(即使你不在C盘装程序),下面就记录几个C盘清理的方法: 1.使用清理软件清理C盘(360卫视,腾讯管家) 2.转移虚拟内存:计算机右键属性——高级管理设置——高级——性能- ...

  9. Objective-C中class、Category、Block的介绍

    @class 当定义一个类,必须为编译器提供两组消息,第一组(接口部分.h):构建类的实例的一个基本蓝图.必须指定类名,类的超类,类的实例变量和类型的列表,最后是类的方法的声明.第二组(实现部分.m) ...

  10. 考研路之C语言

    今天在学习C的时候,又学到了一些新的内容,所以赶紧记录下来. case 1: #include <stdio.h> union exa{ struct{ int a; int b; }ou ...