在其他大部分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();

最新文章

  1. GUI(图形用户界面)
  2. 初学Java之Pattern与Matcher类
  3. 驱动笔记 - IO端口和IO内存
  4. python之supervisord启动脚本
  5. Java循环语句 for
  6. win7桌面图标小盾牌怎么去掉(2种方法)
  7. ASP.NET中的特殊路径标识&quot;~&quot;
  8. poj 1284 Primitive Roots
  9. HDOJ(HDU) 2139 Calculate the formula(水题,又一个用JavaAC不了的题目)
  10. css实现平行四边形、菱形图片效果
  11. 【转】sed &amp; awk常用正则表达式
  12. 一篇关于Maven项目的jar包Shell启动脚本
  13. hdu-5687(字典树)
  14. MT【296】必要性探路
  15. Java并发编程(八)-- 死锁
  16. [dev][https] 非PFS协商的https的流量的解码
  17. 如何杀死oracle死锁进程
  18. mybatis批量删除(逻辑删除)
  19. python之内置函数:map ,filter ,reduce总结
  20. kolla-ansible 源码下载

热门文章

  1. [调试]VS2013调试时提示“运行时当前拒绝计算表达式的值”
  2. 使用chosen插件实现多级联动和置位
  3. pageadmin CMS网站制作教程:
  4. Mac OS 10.12 - ”ln: /usr/bin/tclsh: Operation not permitted“错误的解决方法!!
  5. Flask从入门到精通之使用Flask-Migrate实现数据库迁移
  6. 组件基础—Vue学习笔记
  7. php的GC机制
  8. 从码农升为PM(节约成本)
  9. openerp QWeb
  10. zabbix 调用python脚本监控 磁盘剩余空间(创建模版,创建监控项,创建触发器)