楼主: neozhu

[PL/SQL] 自定义自增序列的并发问题怎么解决

[复制链接]
论坛徽章:
30
生肖徽章:猴
日期:2015-03-20 10:13:49ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:31优秀写手
日期:2015-03-07 06:00:14沸羊羊
日期:2015-03-13 13:26:07美羊羊
日期:2015-04-06 20:32:13天蝎座
日期:2015-07-20 12:34:47射手座
日期:2015-09-18 12:38:55乌索普
日期:2016-08-03 07:04:28奥运会纪念徽章:手球
日期:2016-09-26 07:19:26山治
日期:2016-10-19 05:48:10
21#
发表于 2017-2-27 13:52 | 只看该作者
wmxcn2000 发表于 2017-2-27 11:02
我都这样干:
假定从 1 开始,我会先写入一个从 0 开始的记录,防并且的效果还是不错的,你可以参考一下 ...

-- 生成序列( 1、2、3、4、5) 的记录
update t set num = num + 1 where id = 100 returning num into v_num;

此句UPDATE时因并发使NUM+1的运算结果不等于NUM+UPDATE的次数。
如现在是1,会话A执行UPDATE变2,COMMIT前会话B执行UPDATE变2,两会话COMMIT还是2。

使用道具 举报

回复
论坛徽章:
223
2010新春纪念徽章
日期:2010-03-01 11:20:51ITPUB元老
日期:2019-04-25 13:46:07至尊黑钻
日期:2015-08-13 13:38:12至尊黑钻
日期:2015-02-15 09:47:472015年中国系统架构师大会纪念徽章
日期:2015-07-31 17:48:20管理团队2007贡献徽章
日期:2015-01-19 09:48:272015中国数据库技术大会纪念徽章
日期:2015-05-15 14:08:23海蓝宝石
日期:2015-02-03 10:23:39红宝石
日期:2015-02-03 10:26:04会员2007贡献徽章
日期:2015-02-03 10:26:41
22#
发表于 2017-2-27 14:06 | 只看该作者
阿吉2009 发表于 2017-2-27 13:52
-- 生成序列( 1、2、3、4、5) 的记录
update t set num = num + 1 where id = 100 returning num into ...

不会的,会话1 先执行的  update , 会话2后执行的 update ,如果 会话 1 没有 commit (或rollback),会话2 会等待; 这个是基本的行锁。

使用道具 举报

回复
论坛徽章:
30
生肖徽章:猴
日期:2015-03-20 10:13:49ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:31优秀写手
日期:2015-03-07 06:00:14沸羊羊
日期:2015-03-13 13:26:07美羊羊
日期:2015-04-06 20:32:13天蝎座
日期:2015-07-20 12:34:47射手座
日期:2015-09-18 12:38:55乌索普
日期:2016-08-03 07:04:28奥运会纪念徽章:手球
日期:2016-09-26 07:19:26山治
日期:2016-10-19 05:48:10
23#
发表于 2017-2-27 14:25 | 只看该作者
wmxcn2000 发表于 2017-2-27 14:06
不会的,会话1 先执行的  update , 会话2后执行的 update ,如果 会话 1 没有 commit (或rollback), ...

恩,对,我看懵了。

使用道具 举报

回复
论坛徽章:
1
秀才
日期:2016-11-25 16:52:36
24#
发表于 2017-2-27 14:48 | 只看该作者
感觉思路还是要将并发变成排队运行,如果不想锁表的话,可以考虑新建一个事务处理状态表,每次调用生成序列的过程时,先检查是否有其他会话正在调用此过程。

使用道具 举报

回复
论坛徽章:
1
会员2006贡献徽章
日期:2006-04-17 13:46:34
25#
 楼主| 发表于 2017-2-27 15:00 | 只看该作者
fage090 发表于 2017-2-27 14:48
感觉思路还是要将并发变成排队运行,如果不想锁表的话,可以考虑新建一个事务处理状态表,每次调用生成序列 ...

感觉一个小小递增序列学问还不小呢

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
26#
发表于 2017-2-28 00:12 | 只看该作者
这种做法会使得所有并发事务排队,影响并发性能。如果追求无间隙的序列号这就是必然后果,要么放弃这种需求采用sequence, 要么就忍受性能问题。
在写法上要把update放到第一行,sql%rowcount=0则进行插入,插入时捕获dup_val_on_index异常,发生异常时改做update。

使用道具 举报

回复
27#
发表于 2017-2-28 08:24 | 只看该作者
用自治事务,加锁,根据规则获取序列号,这样序列号不会重复,如果要连续的话业务数据提交时再做检验或者锁之类处理

使用道具 举报

回复
论坛徽章:
30
生肖徽章:猴
日期:2015-03-20 10:13:49ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:31优秀写手
日期:2015-03-07 06:00:14沸羊羊
日期:2015-03-13 13:26:07美羊羊
日期:2015-04-06 20:32:13天蝎座
日期:2015-07-20 12:34:47射手座
日期:2015-09-18 12:38:55乌索普
日期:2016-08-03 07:04:28奥运会纪念徽章:手球
日期:2016-09-26 07:19:26山治
日期:2016-10-19 05:48:10
28#
发表于 2017-2-28 09:00 | 只看该作者
本帖最后由 阿吉2009 于 2017-2-28 09:04 编辑

CREATE OR REPLACE PROCEDURE NEXTSEQNO
(
  P_PREFIX  IN VARCHAR2,
  P_NEXTVAL OUT NUMBER
) IS

BEGIN
  P_NEXTVAL := 1;
  begin
   
    --若前缀不存在则插入,但插入时若因并发前缀已存在则引发违反唯一索引的错误;
    --若前缀已存在则跳过。
    INSERT INTO SEQUENCERS
      SELECT SEQ_ACTION_TYPE.NEXTVAL,
             1,
             P_PREFIX
        FROM DUAL
       WHERE NOT EXISTS (SELECT 1 FROM SEQUENCERS WHERE PREFIX = P_PREFIX);
  
  EXCEPTION
    WHEN DUP_VAL_ON_INDEX then  --违反唯一索引
      UPDATE SEQUENCERS T SET T.SEED = T.SEED + 1 WHERE PREFIX = P_PREFIX RETURNING T.SEED INTO P_NEXTVAL;
   
      COMMIT;
      RETURN;
    WHEN OTHERS THEN
      RAISE;
  END;

  --若因已存在而没插入新记录,则更新后获取新值
  IF SQL%ROWCOUNT = 0 THEN
    UPDATE SEQUENCERS T SET T.SEED = T.SEED + 1 WHERE PREFIX = P_PREFIX RETURNING T.SEED INTO P_NEXTVAL;
  END IF;
  
   COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
    RAISE;
END NEXTSEQNO;


--表结构-- Create table
create table SEQUENCERS
(
  id     NUMBER,
  seed   NUMBER,
  prefix VARCHAR2(1)
)
tablespace MES_DATA
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );
-- Create/Recreate primary, unique and foreign key constraints
alter table SEQUENCERS
  add constraint UQ_PREFIX unique (PREFIX)
  using index
  tablespace MES_DATA
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );

昨天试写了这个过程,多会话测试没问题。大家看有无BUG.

使用道具 举报

回复
论坛徽章:
30
生肖徽章:猴
日期:2015-03-20 10:13:49ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:31优秀写手
日期:2015-03-07 06:00:14沸羊羊
日期:2015-03-13 13:26:07美羊羊
日期:2015-04-06 20:32:13天蝎座
日期:2015-07-20 12:34:47射手座
日期:2015-09-18 12:38:55乌索普
日期:2016-08-03 07:04:28奥运会纪念徽章:手球
日期:2016-09-26 07:19:26山治
日期:2016-10-19 05:48:10
29#
发表于 2017-2-28 09:12 | 只看该作者
象这种带有未知前缀的需求,能否通过用序列等方法解决性能吗?

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
30#
发表于 2017-2-28 23:04 | 只看该作者
alexandre2008 发表于 2017-2-28 08:24
用自治事务,加锁,根据规则获取序列号,这样序列号不会重复,如果要连续的话业务数据提交时再做检验或者锁 ...

自治事务和SEQUENCE一样不能保证无间隙。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表