mysql实现oracle序列

发布于 2019-07-11  424 次阅读


现在都在流行去oracle化,由于oracle没有自增主键这种东西,很多项目在使用oracle时用序列去维护主键。
在迁移mysql后,某些需要提前拿到自增序列并增加自增序列的场景在msyql中就不支持了

一. 实现方案:编写存储过程

存储过程编写

-- 函数说明
-- get_now_and_seize(  
-- 入参:表名(varchar),  
-- 入参:占多少个,防止新插入的占了拿到的主键值(int),  
-- 出参:下一个即将插入的主键值(int));

CREATE PROCEDURE get_now_and_seize(IN v_table_name VARCHAR(50),IN inc_num int, OUT now_auto int)
BEGIN
  -- 开启事务
  start transaction;
  -- 获取下一个即将插入的主键值
  select auto_increment into now_auto from INFORMATION_SCHEMA.TABLES where TABLE_NAME = v_table_name limit 1;
  -- 编写动态sql,占位
  set @sql_1= concat("alter table ",v_table_name," AUTO_INCREMENT=",now_auto+inc_num,";");
  PREPARE stmt FROM @sql_1;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
  commit;
END

测试及使用示例

  1. 测试用表
CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入一些老数据做测试
insert into test (name) value ("ID为1的老数据");
select * from test;
  1. 测试表中当前数据
id   |   name
-----|---------------
1    |  ID为1的老数据
  1. 此时下一个插入的数据的ID应该是2
-- 开始调用获取下一个插入数据的ID并占用多少个的函数
call get_now_and_seize("test",10,@now_seq);
-- 返回2
select @now_seq;
  1. 因为上次从2开始,占10个,下一次插入时应该是12了
insert into test (name) value ("新插入的数据,上边占了10位,我应该是12");
select * from test;
  1. 结果完美
id   |   name
-----|------------------------------------
1    |  ID为1的老数据
12   |  新插入的数据,上边占了10位,我应该是12
  1. Mybatis中使用方法
    方法一:
<select id="getAutoIncAndseize" parameterType="map" statementType="CALLABLE" resultType="java.lang.Object">
    <![CDATA[  
    {call get_now_and_seize(
    #{tableName,mode=IN,jdbcType=VARCHAR},
    #{incNum,mode=IN,jdbcType=INT},
    #{nowInc,mode=OUT,jdbcType=INT},
    )} 
  ]]>
</select>

方法二:
(还没时间测试,有问题的话欢迎大家留言)**

<select id="getAutoIncAndseize" resultType="java.lang.Integer">
    declare @result int
    exec get_now_and_seize #{0},#{1},@result output
    select @result
</select>

二. 实现方案:另维护一张表

这个方法就是要舍弃mysql的自增主键设置,采用另外一张序列表去专门维护主键。
也涉及到一些function啥的
参考:Mysql实现类似Oracle序列

  1. 建立专门的序列维护表
drop table if exists sequence;   
create table sequence (   
    seq_name        VARCHAR(50) NOT NULL, -- 序列名称   
    current_val     INT         NOT NULL, --当前值   
    increment_val   INT         NOT NULL    DEFAULT 1, --步长(跨度)   
    PRIMARY KEY (seq_name)   
);
  1. 实现currval
create function currval(v_seq_name VARCHAR(50))   
returns integer  
begin  
    declare value integer;   
    set value = 0;   
    select current_value into value   
    from sequence  
    where seq_name = v_seq_name;   
    return value;   
end;
-- 使用方法
select currval('seq_name');  
  1. 实现nextval
create function nextval (v_seq_name VARCHAR(50))   
return integer  
begin  
  update sequence  
  set current_val = current_val + increment_val   
  where seq_name = v_seq_name;   
  return currval(v_seq_name);   
end;
-- 使用方法
select nextval('seq_name');  
  1. 增加设置值
create function setval(v_seq_name VARCHAR(50), v_new_val INTEGER)   
returns integer  
begin  
  update sequence  
  set current_val = v_new_val   
  where seq_name = v_seq_name;   
return currval(seq_name);

【马摇金辔破香尘,我自御剑乘风去】