完善在Sybase數據庫上模擬序列對象

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章