zoukankan      html  css  js  c++  java
  • 生成整数自增ID(集群主键生成服务)

        在集群的环境中,有这种场景
        需要整数自增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.效果非常明显.
  • 相关阅读:
    想起来好久没更新博客了
    操作系统文件管理
    PreparedStatement是如何大幅度提高性能的
    Java中快速排序的实现
    详解HashMap的内部工作原理
    关于Java集合的总结
    浅谈JVM内存区域划分
    解决java压缩图片透明背景变黑色的问题
    Vmware15.5中centos7minimal版 窗口字体太小
    字符长度还是字节长度
  • 原文地址:https://www.cnblogs.com/firstdream/p/5222541.html
Copyright © 2011-2022 走看看