在其他大部分DBMS里都有序列的概念,即Sequence或Generator。

而mysql里没有,但有时真的很有用。下面分别用存储过程和函数来模拟序列,并用程序模拟并发场景来测试原子性和完整性,是否能达到预期。

序列表定义如下:

CREATE TABLE `seq` (
`id` BIGINT(20) NOT NULL,
`busi` VARCHAR(50) NULL DEFAULT NULL,
`val` BIGINT(20) NULL DEFAULT NULL,
`remark` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

先把模拟调用程序放这里,因为它是不变的:

            for (int j = ; j < ; j++)
{
Thread t1 = new Thread(() =>
{
for (int i = ; i < ; i++)
{
using (var db = new DbCtxt())
{
//long val = db.Sql("select nextval();").QuerySingle<long>();
long val = db.Sql("call nextval();").QuerySingle<long>();
Console.WriteLine(val+" = "+Thread.CurrentThread.ManagedThreadId);
}
}
});
t1.Start();
}

1、假设存储过程不加事务,读取时不for update

      declare v bigint ;
-- start transaction;
set v = (select val from seq where busi = 'mat');
set v = v + 1;
update seq set val = v where busi = 'mat';
-- commit;
select v;

测试结果:会出现并发读和写数据,现象就是预期序列增加1000,实际每次测试都是增加700~800不定。

2、假设存储过程不加事务,读取时加for update

      declare v bigint ;
-- start transaction;
set v = (select val from seq where busi = 'mat' for update);
set v = v + 1;
update seq set val = v where busi = 'mat';
-- commit;
select v;

测试结果:会出现并发读和写数据,现象就是预期序列增加1000,实际每次测试都是增加700~800不定。

3、假设存储过程加事务,读取时不加for update

      declare v bigint ;
start transaction;
set v = (select val from seq where busi = 'mat' );
set v = v + 1;
update seq set val = v where busi = 'mat';
commit;
select v;

测试结果:每次测试都会出现 Deadlock死锁,并且是很快(val增加不到100)就出现死锁。

4、假设存储过程加事务,读取时也加for update

      declare v bigint ;
start transaction;
set v = (select val from seq where busi = 'mat' for update);
set v = v + 1;
update seq set val = v where busi = 'mat';
commit;
select v;

测试结果:多线程读取,预期序列增加1000,实际每次测试都增加1000,符合预期。

5、用函数模拟,函数不允许显示或隐式的开启事务,先测试读取时不加for update

      declare v bigint ;
-- start transaction;
set v = (select val from seq where busi = 'mat' );
set v = v + 1;
update seq set val = v where busi = 'mat';
-- commit;
return v;

测试结果:多线程读取,预期序列增加1000,实际每次测试都增加1000,符合预期。

6、用函数模拟,测试读取时加for update

      declare v bigint ;
-- start transaction;
set v = (select val from seq where busi = 'mat' for update);
set v = v + 1;
update seq set val = v where busi = 'mat';
-- commit;
return v;

测试结果:多线程读取,预期序列增加1000,实际每次测试都增加1000,符合预期。

总结:若用函数模拟最为简单,不用考虑是否锁定行for update,调用方式 select nextval();

若用存储过程模拟,必须要考虑锁定行for update,且多sql前后要加事务管理,调用方式 call nextval();

mysql 用存储过程和函数分别模拟序列的更多相关文章

  1. MySQL:存储过程和函数

    存储过程和函数 一.创建存储过程和函数 1.创建存储过程 语法: CREATE PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic . ...

  2. MYSQL的存储过程和函数简单写法

    存储过程 MySQL中,创建存储过程的基本形式如下: CREATE PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] ro ...

  3. Mysql中存储过程和函数的写法

    MySQL中,创建存储过程的基本形式如下: CREATE PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine ...

  4. MySQL之存储过程和函数

    存储过程和函数: 1.创建存储过程和函数: 存储过程: delimiter $$ create procedure proc_name() BEGIN 查询语句; // 记得加分号 END $$ de ...

  5. mysql的存储过程,函数,事件,权限,触发器,事务,锁,视图,导入导出

    1.创建过程 1.1 简单创建 -- 创建员工表 DROP TABLE IF EXISTS employee; CREATE TABLE employee( id int auto_increment ...

  6. mySQL查看存储过程、函数、视图、触发器

    一.查看存储过程 1.show procedure status; //查看所有的 2.show create procedure proc_AllUser[proc_name]; 查看proc_Al ...

  7. navicat 给mysql 添加存储过程(函数)

    BEGIN DECLARE i INT default 0; DECLARE num int default 0; DECLARE count1 int default 0; DECLARE coun ...

  8. 我的MYSQL学习心得(十) 自定义存储过程和函数

    我的MYSQL学习心得(十) 自定义存储过程和函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心 ...

  9. MySQL 存储过程和函数

    概述 一提到存储过程可能就会引出另一个话题就是存储过程的优缺点,这里也不做讨论,一般别人问我我就这样回答你觉得它好你就用它.因为mysql中存储过程和函数的语法非常接近所以就放在一起,主要区别就是函数 ...

随机推荐

  1. ie下警告console未定义

    低版本IE6/7/8/9浏览器没有定义console对象,所以代码会中断执行.自己测试,ie11也没有(打开控制台的情况下可以用) 可以用如下代码完美解决. window.console = wind ...

  2. 浅析JS模块规范:AMD,CMD,CommonJS

    from:https://www.jianshu.com/p/09ffac7a3b2c 随着JS模块化编程的发展,处理模块之间的依赖关系成为了维护的关键.   模块化 AMD,CMD,CommonJS ...

  3. ARM 编译工具keil 和 IAR 命令行编译和下载

    目的 不管是Keil还是IAR对代码补全,高亮等编辑功能支持的不是很好,虽然现在的Keil 5.25对界面的支持好了很多,但是很多人还是青睐于第三方的编辑器,命令行的编译方式可以让我们在使用第三方编辑 ...

  4. php不用递归完成无限分类,从表设计入手完整演示过程

    无限分类是什么就不废话了,可以用递归实现,但是递归从数据库取东西用递归效率偏低,如果从表设计入手,就很容易做到网站导航的实现,下面是某论坛导航,如下图 网上无限分类大多不全面,今天我会从设计表开始, ...

  5. max渲染通道元素的范例

    renderElementManager = MaxOps.GetCurRenderElementMgr() renderElementManager.Removeallrenderelements( ...

  6. 【cocos2d-x 手游研发----界面UI设计】

    简单探讨一下如何在cocos2d-x的游戏引擎里面去制作各做交互UI界面,常见的UI如下: 人物头像,血条值,经验条,技能按钮,以及各种玩家交互的界面按钮:背包,人物属性,门派,等: 类似上面的图示交 ...

  7. C++实现排序算法

    稳定性:快速 希尔 选择 堆排序不稳定 时间复杂度:平均情况下,快速.希尔.归并和堆排序的时间复杂度均为O(nlog2(n)),其他都是O(n^2).最坏情况下,快排的时间复杂度为O(n^2) #in ...

  8. VC API常用函数简单例子大全(1-89)

    第一个:FindWindow根据窗口类名或窗口标题名来获得窗口的句柄,该函数返回窗口的句柄 函数的定义:HWND WINAPI FindWindow(LPCSTR lpClassName ,LPCST ...

  9. Mac 设置终端中使用 sublime 打开文件

    在Mac下用终端创建文件等比较方便,但如果配合Sublime用,最好是可以直接在终端中输入命令就可以用Sublime打开指定文件或文件夹. #检查用户目录下有没有bin目录,如里没有就创建一个(目的是 ...

  10. jzoj5906

    我們首先發現,每一條邊都至少走1次,因為我們必須走到每一個節點按按鈕 如果我們不走一個節點,說明這個節點已經有傳送門了,但是必須走到這個節點開傳送門,矛盾 然後我們發現,每一條邊至多經過2次 如果我們 ...