上篇《在Sybase数据库上模拟序列对象》在多线程环境下测试有重复问题。
题记:IAM3.0版本默认的数据库是Oracle,最近在移植到Sybase中遇到问题,Sybase中没有序列,但是又不想修改java代码,如何在Sybase数据库上模拟序列对象呢?
一、创建以下对象
1、创建表SybaseSequences
SybaseSequences保存所有的序列
Create table SybaseSequences (
SeqName nvarchar(255) primary key, -- name of the sequence
Seed int DEFAULT (1) not null, -- seed value
Incr numeric(1,0) DEFAULT (1) not null, -- incremental
Currval numeric(22,0)
)
lock datarows---加上后可以支持行级锁
Go
2、自定义存储过程custom_proc_CreateNewSeq
custom_proc_CreateNewSeq用于添加一个序列,输入参数为SeqName
create procedure custom_proc_CreateNewSeq
@SeqName nvarchar(255),
@seed int = 0,
@incr NUMERIC = 1
--存储过程作用 :在Sybase数据库上模拟Oracle序列对象的创建
--传入参数解释 :
--SeqName 序列的名称
--seed 初始值
--incr 步长
--开发人员 :宋亚坤
--开发时间 :2013-01-15
--修改人 :
--修改事项 :
--修改时间 :
as
begin
declare @currval NUMERIC
/*判断序列是否已经存在*/
if exists (
select 1 from SybaseSequences
where SeqName = @SeqName )
begin
print 'Sequence already exists.'
return 1
end
/*判断初始值和步长并赋给默认值*/
if @seed is null set @seed = 1
if @incr is null set @incr = 1
set @currval = @seed
/*创建序列*/
insert into SybaseSequences (SeqName, Seed, Incr, CurrVal)
values (@SeqName, @Seed, @Incr, @CurrVal)
end
go
3、自定义存储过程custom_proc_GetNewSeqVal
custom_proc_GetNewSeqVal用于生成指定的序列的下一个值,输入参数为SeqName
create procedure custom_proc_GetNewSeqVal
@SeqName nvarchar(255) IN
--存储过程作用 :在Sybase数据库上模拟Oracle序列对象的nextval
--传入参数解释 :
--SeqName 序列的名称
--开发人员 :宋亚坤
--开发时间 :2013-01-15
--修改人 :
--修改事项 :
--修改时间 :
as
begin
declare @NewSeqVal NUMERIC
set NOCOUNT ON
/*根据序列的名称查询到当前序列并锁定当前行*/
select CurrVal from SybaseSequences holdlock where SeqName = left(@SeqName,charindex('.',@SeqName)-1)
/*更新当前序列的CurrVal并返回*/
update SybaseSequences
set @NewSeqVal = CurrVal+Incr,CurrVal = CurrVal+Incr
where SeqName = left(@SeqName,charindex('.',@SeqName)-1)
if @@rowcount = 0
begin
print 'Sequence does not exist'
return
end
return @NewSeqVal
end
---由于传入值为XXX.nextval所以使用 left(@SeqName,charindex('.',@SeqName)-1)
二、验证:
1、创建一个usergroup_sequence序列
custom_proc_CreateNewSeq N'usergroup_sequence'
2、输出usergroup_sequence的当前值,模拟Oracle的nextval
Declare @NewSeqVal NUMERIC
Execute @NewSeqVal=custom_proc_GetNewSeqVal @seqname=N'usergroup_sequence'
3、查询
select * from SybaseSequences where seqname='usergroup_sequence';
三、产品中如何使用:
1、设置存储过程custom_proc_GetNewSeqVal为任意模式
Execute sp_procxmode custom_proc_GetNewSeqVal,anymode
2、创建TestSeq序列
custom_proc_CreateNewSeq N'TestSeq'
3、ibatis配置文件修改
上篇博文中在执行存储过程后再查询虽然可以保证不修改java代码,但是多线程并发测试有重复。
<!-- sybase下根据序列名称获取nextval -->
<parameterMap id="paramMap" class="Map">
<parameter property="currval" jdbcType="VARCHAR" javaType="String" mode="OUT"/>
<parameter property="name" jdbcType="VARCHAR" javaType="String" mode="IN"/>
</parameterMap>
<procedure id="getSequence" parameterMap="paramMap" resultClass="String">
{? = call custom_proc_GetNewSeqVal(?)}
</procedure>
<!-- Oracle下获取序列的nextval -->
<select id="getSequence" resultClass="String"
parameterClass="Map">
select $name$ from dual
</select>
四、总结
这种方法使用一个表来保存所有的应用程序所需的序列,每个序列是一个单独的记录,易于使用和维护, 重新修改后的直接调用过程的实现方式可以支持多线程并发,且不死锁。
注:目前测试100个线程每个线程获取100个序列值下正常。