在ASP.NET程序中創(chuàng)建唯一序號
2024-07-10 13:04:43
供稿:網(wǎng)友
 
如果在程序中需要創(chuàng)建全局唯一的序號,那么必須對創(chuàng)建序號的過程進(jìn)行同步處理,防止多個并發(fā)訪問時出現(xiàn)相同序號的情況。下面列出幾種方法供大家參考。 
  利用數(shù)據(jù)庫的方法
  后面的例子都基于ms sql server,如果使用oracle可以直接讀取sequence對象,則不需要進(jìn)行如此復(fù)雜的操作。
  方法1:利用表鎖定
  表結(jié)構(gòu):
create table xtab (seq_id int primary key, create_time datetime)
  存儲過程或sql語句:
begin tran
declare @max_seq int
--讀出記錄時鎖定表
select @max_seq=max(seq_id) from xtab with (tablockx) 
set @max_seq = isnull(@max_seq,0)
set @max_seq = @max_seq+1
print @max_seq
insert into xtab values(@max_seq,getdate())
commit
--變量@max_seq 中存放的就是當(dāng)前產(chǎn)生的序號 
  方法2:利用自增字段
  如果利用自增變量可以通過方法1中鎖定表,然后再插入記錄,并讀取最大值的方法。不過下面講的是通過c#的ado.net來插入記錄,并讀取已經(jīng)插入的記錄的自增字段。
  表結(jié)構(gòu):
create table xtab_i (seq_id int identity(1,1) primary key, create_time datetime)
  c#代碼,利用時間處理函數(shù)在數(shù)據(jù)被更新時同時讀取@@identity變量的值。完整內(nèi)容參考:oledbwrap.cs 文件。
//參數(shù)內(nèi)容:
//szselectsql = ”select * from xtab_i where seq_id isnull”;
//sztabname = “xtab_i”;
/// <summary>
/// 通過查詢語句 創(chuàng)建dataset對象,返回的對象用于執(zhí)行插入操作
/// </summary>
/// <param name="szselectsql">sql語句</param>
/// <param name="sztabname">表名稱</param>
/// <returns>用于插入的dataset對象</returns>
public dataset createinsertdataset_byselect(string szselectsql,string sztabname){     
 m_dbadapter.selectcommand = new oledbcommand(szselectsql, m_dbconn);
 oledbcommandbuilder cb = new oledbcommandbuilder(m_dbadapter);
 dataset ds = new dataset();
 m_dbadapter.fill(ds, sztabname);
 m_dbadapter.rowupdated += new oledbrowupdatedeventhandler(onrowupdated_inserted);
 return ds;
}
//----------------私有事件處理
/// <summary>
/// 處理數(shù)據(jù)插入的更新事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected void onrowupdated_inserted(object sender, oledbrowupdatedeventargs args)
{
 oledbcommand idcmd = new oledbcommand("select @@identity", m_dbconn);
 if (args.statementtype == statementtype.insert) 
 {
  object robj = idcmd.executescalar(); 
  if(robj == null) m_idbidentity =-1;
  else if( robj.tostring() !="") 
   m_idbidentity = int32.parse(robj.tostring()); 
  else
   m_idbidentity =-1; 
 }
 idcmd.dispose(); 
 //m_idbidentity變量中包含的就是當(dāng)前插入列的自增字段的值
} 
  利用程序控制
  方法1:利用asp.net中的application對象
  利用asp.net中的全局httpapplicationstate對象。
  c#代碼:
application.lock();
application[“xlock”]=”locked’;
try 
{ //必須捕捉異常,避免無法解鎖對象
//your code here
}
catch (exception e) 
{
}
application[“xlock”]=”unlock”; 
  方法2:利用操作系統(tǒng)中的同步對象來實現(xiàn)同步
  在dotnet的框架的system.threading命名空間下定義了多種用于同步的類,例如:mutex,semaphore。下面介紹一下利用互斥對象mutex來實現(xiàn)同步的方法。
  c#代碼:
void test()
{ //需要引入 system.threading;
//創(chuàng)建名為mymutex的互斥對象,如果os已經(jīng)創(chuàng)建過同名對象則只是重新獲得句柄
mutex m = new mutex(false, "mymutex");
//在10秒內(nèi)等待取得訪問權(quán)
boolean getmutex=m.waitone(10*1000,false);
if(getmutex)
{ //已經(jīng)取得訪問權(quán)
 try
 {
  //必須捕捉異常,避免無法解鎖對象
  //your code here
 }
 catch(exception e)
 {
 }
 m.releasemutex();
}
else
{
 //沒有取得訪問權(quán)
}
} 
  在程序中應(yīng)該盡量使用mutex這類可以命名的同步對象以達(dá)到創(chuàng)建多個同步對象,對多種資源進(jìn)行同步的目的。如果要實現(xiàn)多個同入可以使用信號量 semaphore。
  其他方法:利用lock關(guān)鍵字防止線程并發(fā)同一段代碼執(zhí)行
  c#代碼:
class ctest 
{
 int balance;
 void increase() 
 {
  lock (this)
  {
   balance++;
  }
 }
} 
  由于asp.net程序在iis中可能配置不同的線程模式,所以在asp.net程序盡可能不要使用這種方法同步線程,而在普通的應(yīng)用程序中是可以使用這種方法。
   附:oledbwrap.cs ,是一個很簡單的封裝類,封裝了基本的數(shù)據(jù)庫操作。
using system;
using system.data;
using system.data.oledb;
namespace wyy.wrap
{
/// <summary>
/// wdbwrap 說明:完成數(shù)據(jù)庫訪問功能
/// 1 創(chuàng)建connection,adapter,管理對象內(nèi)的conn和adapter對象
/// 2 通過select結(jié)果集填充dataset
/// 3 插入
/// 4 更新
/// </summary>
public class oledbwrap
{
//--------公共方法
/// <summary>
/// 在對象被清除時會自動清除 數(shù)據(jù)庫連接對象
/// </summary>
public oledbwrap()
{
m_dbconn = new oledbconnection(dbstring);
m_fautodelconn = true;
m_dbadapter = new oledbdataadapter();
m_dbconn.open();
}
/// <summary>
/// 通過連接字符串構(gòu)造內(nèi)部的數(shù)據(jù)庫連接對象
/// </summary>
/// <param name="strconnection">ado連接字符串</param>
public oledbwrap(string strconnection)
{
m_dbconn = new oledbconnection(strconnection);
m_fautodelconn = true;
m_dbadapter = new oledbdataadapter();
m_dbconn.open();
}
/// <summary>
/// 通過現(xiàn)有連接構(gòu)造對象,在對象被清除時不會自動清除 數(shù)據(jù)庫連接對象
/// </summary>
/// <param name="conn">現(xiàn)存的數(shù)據(jù)庫連接對象</param>
public oledbwrap(oledbconnection conn)
{
m_dbconn = conn;
m_fautodelconn = false;
m_dbadapter = new oledbdataadapter();
//m_dbconn.open();
}
public virtual void dispose()
{
m_dbadapter.dispose();
if(m_fautodelconn)
{
m_dbconn.close();
m_dbconn.dispose();
}
}
/// <summary>
/// 通過sql語句創(chuàng)建datareader對象
/// </summary>
/// <param name="szsql">sql語句</param>
/// <returns>datareader對象</returns>
public oledbdatareader createdatareader(string szsql)
{
oledbcommand cmd = new oledbcommand(szsql,m_dbconn);
oledbdatareader dr= cmd.executereader();
cmd.dispose();
return dr;
}
/// <summary>
/// 通過sql查詢語句,返回第一行結(jié)果,可以用于執(zhí)行類似與select count(*)的語句
/// </summary>
/// <param name="szsql">sql語句</param>
/// <returns>返回對象</returns>
public object executescalar(string szsql)
{
oledbcommand idcmd = new oledbcommand(szsql, m_dbconn);
object robj = idcmd.executescalar();
idcmd.dispose();
return robj;
}
/// <summary>
/// 調(diào)用oledbcommand 的 executenonquery
/// </summary>
/// <param name="szsql"></param>
/// <returns></returns>
public int executenonquery(string szsql)
{
oledbcommand idcmd = new oledbcommand(szsql, m_dbconn);
int iret = idcmd.executenonquery();
idcmd.dispose();
return iret;
}
/// <summary>
/// 創(chuàng)建查詢用dataset對象
/// </summary>
/// <param name="szsql">查詢sql語句</param>
/// <param name="sztabname">表名稱</param>
/// <returns>已經(jīng)被填充的dataset對象</returns>
public dataset createselectdataset(string szsql,string sztabname)
{
m_dbadapter.selectcommand = new oledbcommand(szsql,m_dbconn);
dataset ds = new dataset();
m_dbadapter.fill(ds,sztabname);
return ds;
}
/// <summary>
/// 通過查詢語句 創(chuàng)建dataset對象,返回的對象用于執(zhí)行插入操作
/// </summary>
/// <param name="szselectsql">sql語句</param>
/// <param name="sztabname">表名稱</param>
/// <returns>用于插入的dataset對象</returns>
public dataset createinsertdataset_byselect(string szselectsql,string sztabname)
{
m_dbadapter.selectcommand = new oledbcommand(szselectsql, m_dbconn);
oledbcommandbuilder cb = new oledbcommandbuilder(m_dbadapter);
dataset ds = new dataset();
m_dbadapter.fill(ds, sztabname);
m_dbadapter.rowupdated += new oledbrowupdatedeventhandler(onrowupdated_inserted);
return ds;
}
/// <summary>
/// 通過查詢語句 創(chuàng)建dataset對象,返回的對象用于執(zhí)行更新操作
/// </summary>
/// <param name="szselectsql">sql語句</param>
/// <param name="sztabname">表名稱</param>
/// <returns>用于更新的dataset對象</returns>
public dataset createupdatedataset_byselect(string szselectsql,string sztabname)
{
m_dbadapter.selectcommand = new oledbcommand(szselectsql, m_dbconn);
oledbcommandbuilder cb = new oledbcommandbuilder(m_dbadapter);
dataset ds = new dataset();
m_dbadapter.fill(ds, sztabname);
return ds;
//m_dbadapter.rowupdated += new oledbrowupdatedeventhandler(onrowupdated_update);
}
//----------------私有事件處理
/// <summary>
/// 處理數(shù)據(jù)插入的更新事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected void onrowupdated_inserted(object sender, oledbrowupdatedeventargs args)
{
oledbcommand idcmd = new oledbcommand("select @@identity", m_dbconn);
if (args.statementtype == statementtype.insert)
{
object robj = idcmd.executescalar();
if(robj == null)
m_idbidentity =-1;
else if( robj.tostring() !="")
m_idbidentity = int32.parse(robj.tostring());
else
m_idbidentity =-1;
}
idcmd.dispose();
}
//------------公共屬性
/// <summary>
/// 在插入數(shù)據(jù)后獲取新數(shù)據(jù)行中自增字段的值,目前只能支持一個自增字段
/// </summary>
public int32 dbidentity {get{return m_idbidentity;} }
/// <summary>
/// 數(shù)據(jù)庫連接字符串,保存在web.config文件中 <appsettings>節(jié)
/// </summary>
public string dbstring {get{return system.configuration.configurationsettings.appsettings["dbstr"];}}
//------------公共變量
/// <summary>
/// 數(shù)據(jù)庫連接
/// </summary>
public oledbconnection m_dbconn;
/// <summary>
/// 查詢adapter
/// </summary>
public oledbdataadapter m_dbadapter;
public const string m_szrooturl ="/copathway/todo/";
//---------- 私有變量
/// <summary>
/// 保存數(shù)據(jù)庫插入是自增字段的值
/// </summary>
protected int32 m_idbidentity =-1;
protected bool m_fautodelconn = true;
}
}