上篇《在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個序列值下正常。