mysql序列(这里只谈innodb引擎)

  1. 在使用mysql的AUTO_INCREMENT时,使用AUTO_INCREMENT的字段必须建有索引,也可以为索引的一部分。当没有索引时会报错:          由于mysql是索引组织表,数据存放在主键中,又由于自增列字段内容长度较小,建议选用自增字段为主键。
  2. 对于mysql来说AUTO_INCREMENT 的加锁模式是由参数innodb_autoinc_lock_mode决定的,不同的加锁模式加上的不同的insert方式对mysql产生不同的影响,insert的类型包括:Simple inserts、Bulk inserts、Mixed-mode inserts三种。innodb_autoinc_lock_mode的取值有0,1,2三种。
    1. innodb_autoinc_lock_mode=0时:

      • In this lock mode, all “INSERT-like” statements obtain a special table-level AUTO-INC lock for inserts into tables with AUTO_INCREMENT columns。在这种锁模式下,所有的insert类型的语句,对于AUTO_INCREMENT列均加有特殊的表锁AUTO-INC锁
      • 这种锁模式在语句结束时结束,并非在事务结束时结束。这样可以保证每个auto-increment是在可预测,可重复的模式情况下赋值,也可以保证对于任何insert类语句,每个auto-increment列的赋值都是连续的。
      • 虽然这种锁模式下,可以保证auto-increment的连续性,但由于加的是表锁,所以对并发性影响较大。
    2. innodb_autoinc_lock_mode =1 时:
      • 在该模式下,bulk inserts添加的 AUTO-INC表锁,并一直持续到语句结束。这是适用于 INSERT ... SELECT,REPLACE ... SELECT LOAD DATA语句。
      • 对于事前知道插入多少行的Simple inserts,则可以避免AUTO-INC表锁,它加的是轻量级的锁mutex ,只会在自增列值分配时存在,不会等到语句执行结束。
      • 对于Mixed-mode inserts,innodb会分配比插入的行更多的auto-increment值,但分配的值是连续的。
    3. innodb_autoinc_lock_mode =2 时:
      • 在这种锁模式下,对于所有insert 类型的语句都不会加AUTO-INC表锁,这是最快和最具伸缩性的模式。但是当在binlog是statement格式下时,这种模式是不安全的。
      • 在这种锁模式下,auto-increment值可以保证是唯一和单调的递增的,即使存在并发的insert类型操作时,auto-increment值不连续的情况。

  3、(1)当在statement-based复制下时,innodb_autoinc_lock_mode为0或1,均可以保证主从序列的一致性。当配置的innodb_autoinc_lock_mode=2或是主从不一样时,则主从序列值不能保证一致。

    (2)如果使用的是row-based 或 mixed-format复制,则auto-increment的锁模式都是安全的,因为基于row-based的复制是不受sql语句执行顺序的影响的。

    (3)如果在事务中含有auto-increment的分配语句回滚了,那分配的auto-increment值也就消失了,不能再被使用。auto-increment值是不会被回滚的。

    (4)当在AUTO_INCREMENT列插入的值是NULL或0时,AUTO_INCREMENT都会分配一个新值。

    (5)当插入的值是负值时,也可以正常插入,由于mysql是索引组织表,插入的负值会插在其他正值的前面.

    (6)当做bulk inserts操作,且innodb_autoinc_lock_mode为0或1此时AUTO_INCREMENT值不会产生间隙,因为此时添加的是表锁。innodb_autoinc_lock_mode=2时,则可能产生间隙。

    (7)对于mixed-mode inserts,innodb_autoinc_lock_mode不同的值会有不同的情况:

    下面是创建的测试表:

  该表最新自动产生的序列值是100:

  1. mysql> CREATE TABLE t1 (
  2. -> c1 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  3. -> c2 CHAR(1)
  4. -> ) ENGINE = INNODB;
  5.  
  6. mysql> INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
      • 当innodb_autoinc_lock_mode=0时:

        1. mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
        2. +-----+------+
        3. | c1 | c2 |
        4. +-----+------+
        5. | 1 | a |
        6. | 101 | b |
        7. | 5 | c |
        8. | 102 | d |
        9. +-----+------+

        后面自动分配的将是103,因为auto-increment值一次分配一个,而不是分配了所有的值。无论是否并发,结果均如此。

      • 当innodb_autoinc_lock_mode=1时:
        1. mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
        2. +-----+------+
        3. | c1 | c2 |
        4. +-----+------+
        5. | 1 | a |
        6. | 101 | b |
        7. | 5 | c |
        8. | 102 | d |
        9. +-----+------+

        后面自动分配的将是105,不是103,这是因为在语句执行时,就已将4个自增值分配了,而不仅仅是使用到的两个值。无论是否并发,结果均如此。

      • 当innodb_autoinc_lock_mode=2时:
        1. mysql> SELECT c1, c2 FROM t1 ORDER BY c2;
        2. +-----+------+
        3. | c1 | c2 |
        4. +-----+------+
        5. | 1 | a |
        6. | x | b |
        7. | 5 | c |
        8. | y | d |
        9. +-----+------+

        在分配时,x和y将是惟一的,而且比前面的值要大,然后这里的x和y值将受到并发insert操作的影响。假如当前序列分配的值是4,则x将为5,与后面的5值相同,报错,后面的(5,c)将插入失败。

         

pg序列:

  下面是pg创建序列的语法:

  1. CREATE [ TEMPORARY | TEMP ] SEQUENCE name [ INCREMENT [ BY ] increment ]
  2. [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
  3. [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
  4. [ OWNED BY { table_name.column_name | NONE } ]

序列中各参数具体含义请参考官方文档,这里主要讲解几个参数:

  cache:

  cache是指预分配几个序列值,放在内存中,以方便序列的快速分配。没有指定时,默认值是1.当该值设置大于1时,多个session同时做高并发insert时,每个session都会预分配cache个序列值,但不见得每个预分配的序列值会被使用,所以会出现序列值不连续的情况。不过pg序列已专门做过优化,cache加大效果不大,后面会有介绍。

  CYCLE:

  这个参数用于,当序列值递增至最大值或递减(当increment为负值时)至最小值时,是否循环从设定的最大值或最小值开始。pg序列默认的最大值是:9223372036854775807,pg序列默认是基于bigint类型创建的。当超过该值并且没有设定CYCLE时,会报错。默认是NO CYCLE.

  另外需要注意的时,在使用setval重设序列值时,其他session将不会受影响,直到cache预分配的值使用完毕后。

测试CYCLE对序列的影响:

  创建一个序列:

  选项均使用默认值。看到is_cycled是f,默认是NO CYCLE的。 

  1. swrd=# create sequence seq1;
  2. CREATE SEQUENCE
  3. swrd=# \d seq1
  4. Sequence "swrd.seq1"
  5. Column | Type | Value
  6. ---------------+---------+---------------------
  7. sequence_name | name | seq1
  8. last_value | bigint | 1
  9. start_value | bigint | 1
  10. increment_by | bigint | 1
  11. max_value | bigint | 9223372036854775807
  12. min_value | bigint | 1
  13. cache_value | bigint | 1
  14. log_cnt | bigint | 0
  15. is_cycled | boolean | f
  16. is_called | boolean | f

将该序列修改成递减,并将当前值修改5.

  1. swrd=# alter sequence seq1 increment -1;
  2. ALTER SEQUENCE
  3. swrd=# select setval('seq1',5);
  4. setval
  5. --------
  6. 5
  7. (1 row)
  8.  
  9. swrd=# \d seq1
  10. Sequence "swrd.seq1"
  11. Column | Type | Value
  12. ---------------+---------+---------------------
  13. sequence_name | name | seq1
  14. last_value | bigint | 5
  15. start_value | bigint | 1
  16. increment_by | bigint | -1
  17. max_value | bigint | 9223372036854775807
  18. min_value | bigint | 1
  19. cache_value | bigint | 1
  20. log_cnt | bigint | 0
  21. is_cycled | boolean | f
  22. is_called | boolean | t

下面不断的取下一个序列值:

  1. swrd=# select nextval('seq1');
  2. nextval
  3. ---------
  4. 4
  5. (1 row)
  6.  
  7. swrd=# select nextval('seq1');
  8. nextval
  9. ---------
  10. 3
  11. (1 row)
  12.  
  13. swrd=# select nextval('seq1');
  14. nextval
  15. ---------
  16. 2
  17. (1 row)
  18.  
  19. swrd=# select nextval('seq1');
  20. nextval
  21. ---------
  22. 1
  23. (1 row)
  24.  
  25. swrd=# select nextval('seq1');
  26. ERROR: nextval: reached minimum value of sequence "seq1" (1)

当取到1时,由于不是循环的,最后报错,达到默认的最小值。

现将序列修改为CYCLE,然后取下一个值:

  1. swrd=# alter sequence seq1 cycle;
  2. ALTER SEQUENCE
  3. swrd=# \d seq1
  4. Sequence "swrd.seq1"
  5. Column | Type | Value
  6. ---------------+---------+---------------------
  7. sequence_name | name | seq1
  8. last_value | bigint | 1
  9. start_value | bigint | 1
  10. increment_by | bigint | -1
  11. max_value | bigint | 9223372036854775807
  12. min_value | bigint | 1
  13. cache_value | bigint | 1
  14. log_cnt | bigint | 0
  15. is_cycled | boolean | t
  16. is_called | boolean | t
  17.  
  18. swrd=# select nextval('seq1');
  19. nextval
  20. ---------------------
  21. 9223372036854775807
  22. (1 row)
  23.  
  24. swrd=# select nextval('seq1');
  25. nextval
  26. ---------------------
  27. 9223372036854775806
  28. (1 row)

设定循环后,可以继续往下取值,不会报错。递增的情况也与此类似。所以对数据库序列的定期巡检是有必要的,对于快达到最小或最大值的序列要及时处理,以免影响业务访问。

sequence与serial:

  serial并不是pg的数据类型,但它可以用来方便的创建序列。

  下面的两种方式是等价的:

  使用serial:

  1. swrd=# create table test_serial(id serial);
  2. CREATE TABLE
  3. swrd=# \d test_serial
  4. Table "swrd.test_serial"
  5. Column | Type | Modifiers
  6. --------+---------+----------------------------------------------------------
  7. id | integer | not null default nextval('test_serial_id_seq'::regclass)
  8.  
  9. swrd=# \d test_serial_id_seq
  10. Sequence "swrd.test_serial_id_seq"
  11. Column | Type | Value
  12. ---------------+---------+---------------------
  13. sequence_name | name | test_serial_id_seq
  14. last_value | bigint | 1
  15. start_value | bigint | 1
  16. increment_by | bigint | 1
  17. max_value | bigint | 9223372036854775807
  18. min_value | bigint | 1
  19. cache_value | bigint | 1
  20. log_cnt | bigint | 0
  21. is_cycled | boolean | f
  22. is_called | boolean | f
  23. Owned by: swrd.test_serial.id

  使用sequence:

  1. swrd=# create sequence test_seq_id ;
  2. CREATE SEQUENCE
  3. swrd=# create table test_seq(id int not null default nextval('test_seq_id'));
  4. CREATE TABLE
  5. swrd=# alter sequence test_seq_id owned by test_seq.id;
  6. ALTER SEQUENCE
  7. swrd=# \d test_seq
  8. Table "swrd.test_seq"
  9. Column | Type | Modifiers
  10. --------+---------+---------------------------------------------------
  11. id | integer | not null default nextval('test_seq_id'::regclass)
  12.  
  13. swrd=# \d test_seq_id
  14. Sequence "swrd.test_seq_id"
  15. Column | Type | Value
  16. ---------------+---------+---------------------
  17. sequence_name | name | test_seq_id
  18. last_value | bigint | 1
  19. start_value | bigint | 1
  20. increment_by | bigint | 1
  21. max_value | bigint | 9223372036854775807
  22. min_value | bigint | 1
  23. cache_value | bigint | 1
  24. log_cnt | bigint | 0
  25. is_cycled | boolean | f
  26. is_called | boolean | f
  27. Owned by: swrd.test_seq.id

注意:

  1、在创建外部表时,当主表存在含有序列的列,则外部表创建时,可以使用sequence创建序列,但不能使用serial创建。这个问题会在另一篇博客中讲解。

  2、当使用serial创建的id列,删除时,创建时对应的序列也会一并删除,但单独使用sequence创建的序列则不会。

  3、但不论是使用哪种方式创建的序列,当删除序列时,都会提示存在依赖关系,提示使用CASCADE一并将依赖对象删除。要想不删除依赖的表,可以将default值去掉。然后单独删除序列。

测试cache对序列的影响:

这里创建两个序列一个cache使用默认值1,另一个序列将cache值设为100.

  1. postgres=# create sequence seq1;
  2. CREATE SEQUENCE
  3. postgres=# create sequence cached_seq cache 100;
  4. CREATE SEQUENCE

测试10、100个并发时的情况:

1.sql文件中的内容是:select nextval('seq1'),2.sql文件中的内容是:select nextval('cached_seq')

10个并发时:

  1. postgres@db-> pgbench -n -c -j -T -f .sql
  2. transaction type: Custom query
  3. scaling factor:
  4. query mode: simple
  5. number of clients:
  6. number of threads:
  7. duration: s
  8. number of transactions actually processed:
  9. latency average: 0.124 ms
  10. tps = 80482.444739 (including connections establishing)
  11. tps = 87140.735942 (excluding connections establishing)
  12. postgres@db-----> pgbench -n -c -j -T -f .sql
  13. transaction type: Custom query
  14. scaling factor:
  15. query mode: simple
  16. number of clients:
  17. number of threads:
  18. duration: s
  19. number of transactions actually processed:
  20. latency average: 0.119 ms
  21. tps = 84295.675509 (including connections establishing)
  22. tps = 90538.479485 (excluding connections establishing)

10个并发时,cache使用默认值tps为87140.735942,cache值为100的tps是:90538.479485,两者相差不大。

100个并发时:

  1. postgres@db-> pgbench -n -c -j -T -f .sql
  2. transaction type: Custom query
  3. scaling factor:
  4. query mode: simple
  5. number of clients:
  6. number of threads:
  7. duration: s
  8. number of transactions actually processed:
  9. latency average: 1.467 ms
  10. tps = 63938.069494 (including connections establishing)
  11. tps = 161793.078271 (excluding connections establishing)
  12. postgres@db-> pgbench -n -c -j -T -f .sql
  13. transaction type: Custom query
  14. scaling factor:
  15. query mode: simple
  16. number of clients:
  17. number of threads:
  18. duration: s
  19. number of transactions actually processed:
  20. latency average: 1.230 ms
  21. tps = 80642.482598 (including connections establishing)
  22. tps = 163479.402068 (excluding connections establishing)

100个并发时,默认cache值时的tps为:161793.078271,cache为100的tps为:163479.402068,两者相差更小了。

注:

  1、按照对cache选项的理解,cache越大,性能越高才对,但测试发现cache对性能影响不大。

  2、既然cache对序列的性能提高不大,那尽量cache使用默认值1,以避免出现序列值的不连续性。

  3、pg序列的如此高效性,接近redis的INCRs。具体可参考Don’t Assume PostgreSQL is Slow

pg序列可以这么快及cache作用不大的原因:

在pg源码src/backend/commands/sequence.c中可以看到:

  1. /*
  2. * We don't want to log each fetching of a value from a sequence,
  3. * so we pre-log a few fetches in advance. In the event of
  4. * crash we can lose (skip over) as many values as we pre-logged.
  5. */
  6. #define SEQ_LOG_VALS 32
  1. /*
    * Decide whether we should emit a WAL log record. If so, force up the
  2. * fetch count to grab SEQ_LOG_VALS more values than we actually need to
  3. * cache. (These will then be usable without logging.)
  4. *
  5. * If this is the first nextval after a checkpoint, we must force a new
  6. * WAL record to be written anyway, else replay starting from the
  7. * checkpoint would fail to advance the sequence past the logged values.
  8. * In this case we may as well fetch extra values.
  9. */
  10. if (log < fetch || !seq->is_called)
  11. {
  12. /* forced log to satisfy local demand for values */
  13. fetch = log = fetch + SEQ_LOG_VALS;
  14. logit = true;
  15. }
  16. else
  17. {
  18. XLogRecPtr redoptr = GetRedoRecPtr();
  19.  
  20. if (PageGetLSN(page) <= redoptr)
  21. {
  22. /* last update of seq was before checkpoint */
  23. fetch = log = fetch + SEQ_LOG_VALS;
  24. logit = true;
  25. }
  26. }
  1. /*
  2. * We don't log the current state of the tuple, but rather the state
  3. * as it would appear after "log" more fetches. This lets us skip
  4. * that many future WAL records, at the cost that we lose those
  5. * sequence values if we crash.
  6. */
  7. XLogBeginInsert();
  8. XLogRegisterBuffer(, buf, REGBUF_WILL_INIT);
  9.  
  10. /* set values that will be saved in xlog */
  11. seq->last_value = next;
  12. seq->is_called = true;
  13. seq->log_cnt = ;
  14.  
  15. xlrec.node = seqrel->rd_node;
  16.  
  17. XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
  18. XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
  19.  
  20. recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
  21.  
  22. PageSetLSN(page, recptr);
  1. }
  2. /* Now update sequence tuple to the intended final state */
  3. seq->last_value = last; /* last fetched number */
  4. seq->is_called = true;
  5. seq->log_cnt = log; /* how much is logged */

可以看到pg中并不是每产生一个序列值就做一次记录wal log的操作,而是每产生32个序列值后才会记一次wal log record。所以这相当于已对序列做了缓存。

其中log_cnt扮演者计数器的角色,当该值减为0时,则会产生一个记录wal log的标志位。该计数器对应的是序列属性中的log_cnt。

  1. swrd=# \d seq1
  2. Sequence "swrd.seq1"
  3. Column | Type | Value
  4. ---------------+---------+---------------------
  5. sequence_name | name | seq1
  6. last_value | bigint | 9223372036854775806
  7. start_value | bigint | 1
  8. increment_by | bigint | -1
  9. max_value | bigint | 9223372036854775807
  10. min_value | bigint | 1
  11. cache_value | bigint | 1
  12. log_cnt | bigint | 31
  13. is_cycled | boolean | t
  14. is_called | boolean | t

每产生一个序列值该值就减1。但当服务器意外宕机时,则会丢掉代码中缓存的序列值。

下面做个测试:

当前序列seq的值为15:

  1. swrd=# select nextval('seq1');
  2. nextval
  3. ---------
  4. 15
  5. (1 row)
  6.  
  7. swrd=# \d seq1
  8. Sequence "swrd.seq1"
  9. Column | Type | Value
  10. ---------------+---------+---------------------
  11. sequence_name | name | seq1
  12. last_value | bigint | 15
  13. start_value | bigint | 1
  14. increment_by | bigint | 1
  15. max_value | bigint | 9223372036854775807
  16. min_value | bigint | 1
  17. cache_value | bigint | 1
  18. log_cnt | bigint | 32
  19. is_cycled | boolean | t
  20. is_called | boolean | t

它的下个值应为16,而且还有32个值没有分配,此时模拟数据库意外宕机,将数据库的进程强制杀掉:

  1. swrd=# \d seq1
  2. Sequence "swrd.seq1"
  3. Column | Type | Value
  4. ---------------+---------+---------------------
  5. sequence_name | name | seq1
  6. last_value | bigint | 47
  7. start_value | bigint | 1
  8. increment_by | bigint | 1
  9. max_value | bigint | 9223372036854775807
  10. min_value | bigint | 1
  11. cache_value | bigint | 1
  12. log_cnt | bigint | 0
  13. is_cycled | boolean | t
  14. is_called | boolean | t
  15.  
  16. swrd=# select nextval('seq1');
  17. nextval
  18. ---------
  19. 48
  20. (1 row)

强制杀掉pg后,再启动发现当前序列的值是47,及缓存的32加上之前的序列值15,再执行nextval,下一个序列值是48.

 pg迁移时的序列

当进行pg迁移时可能存在序列字段恰好是主键的表的情况,迁移完成后,一定要检查有无这种情况,将序列值设置为主键值的max值,如果产生的序列值小于主键max值的情况,则数据将插入不进去。

pg与mysql序列比较:

  1、pg的序列属性是基于单表,而mysql则是基于整个实例的。

  2、pg的序列不必建有主键,而mysql多为建有主键索引,所以不存在重复的情况,而pg则会存在。

  3、pg的序列高并发时效率非常高,不会出现锁表的情况,而mysql则要视insert的类型、参数innodb_autoinc_lock_mode的值和binlog的格式设定情况来看。

  4、pg中可以限定序列值达到限定的最大值或最小值时CYCLE使用,mysql则可以通过修改字段类型为unsigned或是将字段类型更改为更大范围的类型,没有看到CYCLE的用法。

  5、pg中序列值可递减,而mysql中序列值开始值和增加值均必须为正数,范围均为1 .. 65535。由两个参数控制:auto_increment_offset控制从哪个值开始,auto_increment_increment:控制每次递增的量。

  6、pg的序列与mysql的序列均不能回滚。

  7、pg的序列字段不一定要创建索引,但mysql则必须创建。

参考:

https://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html

https://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html

https://www.postgresql.org/docs/9.4/static/sql-createsequence.html

https://www.postgresql.org/docs/9.4/static/sql-altersequence.html

https://www.postgresql.org/docs/9.4/static/functions-sequence.html

https://www.postgresql.org/docs/9.4/static/datatype-numeric.html

http://blog.chinaunix.net/uid-20726500-id-4727557.html?spm=5176.100239.blogcont.6.DBlloS

src/backend/commands/sequence.c

https://yq.aliyun.com/articles/6053?do=login

mysql 序列与pg序列的比较的更多相关文章

  1. r语言之生成规则序列,规则序列函数及用法

    在生成序列时,“:”的优先级最高 (1)从1到20的整数序列: > 1:20 [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (2) ...

  2. firedac二进制序列和JSON序列的对比

    firedac二进制序列和JSON序列的对比 以同样大小的一个数据集的数据,作为测试的数据. 以JSON序列后的数据体积是4958字节. 以二进制序列后的数据体积是3044字节. 4958/3044= ...

  3. Gym 101064 D Black Hills golden jewels 【二分套二分/给定一个序列,从序列中任意取两个数形成一个和,两个数不可相同,要求求出第k小的组合】

    D. Black Hills golden jewels time limit per test 2 seconds memory limit per test 256 megabytes input ...

  4. Python——序列封包与序列解包

    一.序列封包与序列解包 把多个值赋给一个变量时,Python会自动的把多个值封装成元组,称为序列封包. 把一个序列(列表.元组.字符串等)直接赋给多个变量,此时会把序列中的各个元素依次赋值给每个变量, ...

  5. 扩增子分析解读4去嵌合体 非细菌序列 生成代表性序列和OTU表

    本节课程,需要先完成 扩增子分析解读1质控 实验设计 双端序列合并 2提取barcode 质控及样品拆分 切除扩增引物 3格式转换 去冗余 聚类   先看一下扩增子分析的整体流程,从下向上逐层分析 分 ...

  6. Oracle和Mysql分别生成sequence序列

    有时候在往数据库中插入数据的时候,如果ID值是32位的UUID, 而自己随便写个字符又不合适,这时就要用到函数来产生一个序列值 Oracle: select sys_guid() from dual; ...

  7. [YY]已知逆序列求原序列(二分,树状数组)

    在看组合数学,看到逆序列这个概念.于是YY了一道题:已知逆序列,求出原序列. 例子: 元素个数 n = 8 逆序列 a={5,3,4,0,2,1,1,0} 则有原序列 p={4,8,6,2,5,1,3 ...

  8. 一个序列是否可能是push序列的pop序列

    输入:两个序列A.B,A作栈的push序列,判断B是否可能是A的pop序列. #include<iostream> #include<stack> using namespac ...

  9. 第29题:推断一个序列是否是还有一个push序列的pop序列

    github:https://github.com/frank-cq/MyTest 第29题:输入两个整数序列,当中一个序列表示栈的push顺序,推断还有一个序列有没有可能是相应的pop顺序.为了简单 ...

随机推荐

  1. Read Excel file from C#

    Common way is: var fileName = string.Format("{0}\\fileNameHere", Directory.GetCurrentDirec ...

  2. java语法基本知识2

    对象的引用相当于C中的指针.对象存在于堆中,引用存在于栈中.引用在函数,可以称作局部变量.

  3. 安全协议系列(二)----CCM与CCMP

    CCMP(CTR with CBC-MAC Protocol) 是 IEEE 802.11i 中推出使用基于 AES 的 CCM 模式的安全加密协议.与原来脆弱的 WEP 算法及临时补救措施 TKIP ...

  4. .NET将图片Base64字符串还原为图片(jpg格式)并保存到本地

    1. 了解Base64字符串的形式是:data:image/jpeg;base64,字符串 2 .Base64字符串转换为图片的代码实现: string[] str = base64Str.Split ...

  5. 认识Java

    java出生地:SUN Microsystems Inc<开源>     -SUN : Standford University Network java之父:James Gosling ...

  6. HTTP简介

    HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议.. HT ...

  7. C# Substring的用法

    方法1  Substring(Int32) 从此实例检索子字符串. 子字符串在指定的字符位置开始并一直到该字符串的末尾. 方法2 Substring(Int32, Int32) 从此实例检索子字符串. ...

  8. vs2013提高编译速度

    最近做新的项目,很多库是之前项目积累下来的库.在windows下使用的IDE是vs2013,整体编译的时候,明显感觉编译速度较慢,文件是一个一个编的. 从编译器本身的角度,vs2013是提供了加快编译 ...

  9. gcc编译的四个阶段:预处理,编译,汇编,链接

    1:gcc编译的四个阶段:预处理,编译,汇编,链接 #vi file.c #gcc -E file.c -o file.i//-E查看且预处理后停止编译,-o生成目标文件,-i表示已预处理 #gcc  ...

  10. tomcat端口号被占用或者修改端口号的解决方法

    一)修改端口号: 在tomcat文件中找到conf里面的server.xml 在tomcat解压后的文件中按照下图操作