首页 > 编程 > .NET > 正文

在ASP.NET程序中创建唯一序号

2024-07-10 13:04:43
字体:
来源:转载
供稿:网友
如果在程序中需要创建全局唯一的序号,那么必须对创建序号的过程进行同步处理,防止多个并发访问时出现相同序号的情况。下面列出几种方法供大家参考。

  利用数据库的方法

  后面的例子都基于ms sql server,如果使用oracle可以直接读取sequence对象,则不需要进行如此复杂的操作。

  方法1:利用表锁定

  表结构:

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 中存放的就是当前产生的序号

  方法2:利用自增字段

  如果利用自增变量可以通过方法1中锁定表,然后再插入记录,并读取最大值的方法。不过下面讲的是通过c#的ado.net来插入记录,并读取已经插入的记录的自增字段。

  表结构:

create table xtab_i (seq_id int identity(1,1) primary key, create_time datetime)

  c#代码,利用时间处理函数在数据被更新时同时读取@@identity变量的值。完整内容参考:oledbwrap.cs 文件。


//参数内容:
//szselectsql = ”select * from xtab_i where seq_id isnull”;
//sztabname = “xtab_i”;
/// <summary>
/// 通过查询语句 创建dataset对象,返回的对象用于执行插入操作
/// </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>
/// 处理数据插入的更新事件
/// </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变量中包含的就是当前插入列的自增字段的值
}

  利用程序控制

  方法1:利用asp.net中的application对象

  利用asp.net中的全局httpapplicationstate对象。

  c#代码:


application.lock();

application[“xlock”]=”locked’;

try

{ //必须捕捉异常,避免无法解锁对象

//your code here

}

catch (exception e)

{

}

application[“xlock”]=”unlock”;

  方法2:利用操作系统中的同步对象来实现同步

  在dotnet的框架的system.threading命名空间下定义了多种用于同步的类,例如:mutex,semaphore。下面介绍一下利用互斥对象mutex来实现同步的方法。

  c#代码:


void test()
{ //需要引入 system.threading;
//创建名为mymutex的互斥对象,如果os已经创建过同名对象则只是重新获得句柄

mutex m = new mutex(false, "mymutex");
//在10秒内等待取得访问权
boolean getmutex=m.waitone(10*1000,false);
if(getmutex)
{ //已经取得访问权
 try
 {
  //必须捕捉异常,避免无法解锁对象
  //your code here
 }
 catch(exception e)
 {
 }
 m.releasemutex();
}
else
{
 //没有取得访问权
}

}

  在程序中应该尽量使用mutex这类可以命名的同步对象以达到创建多个同步对象,对多种资源进行同步的目的。如果要实现多个同入可以使用信号量 semaphore。

  其他方法:利用lock关键字防止线程并发同一段代码执行

  c#代码:


class ctest
{
 int balance;
 void increase()
 {
  lock (this)
  {
   balance++;
  }
 }
}

  由于asp.net程序在iis中可能配置不同的线程模式,所以在asp.net程序尽可能不要使用这种方法同步线程,而在普通的应用程序中是可以使用这种方法。

   附:oledbwrap.cs ,是一个很简单的封装类,封装了基本的数据库操作。


using system;
using system.data;
using system.data.oledb;

namespace wyy.wrap
{
/// <summary>
/// wdbwrap 说明:完成数据库访问功能
/// 1 创建connection,adapter,管理对象内的conn和adapter对象
/// 2 通过select结果集填充dataset
/// 3 插入
/// 4 更新
/// </summary>
public class oledbwrap
{
//--------公共方法
/// <summary>
/// 在对象被清除时会自动清除 数据库连接对象
/// </summary>
public oledbwrap()
{
m_dbconn = new oledbconnection(dbstring);
m_fautodelconn = true;
m_dbadapter = new oledbdataadapter();
m_dbconn.open();
}
/// <summary>
/// 通过连接字符串构造内部的数据库连接对象
/// </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>
/// 通过现有连接构造对象,在对象被清除时不会自动清除 数据库连接对象
/// </summary>
/// <param name="conn">现存的数据库连接对象</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语句创建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查询语句,返回第一行结果,可以用于执行类似与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>
/// 调用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>
/// 创建查询用dataset对象
/// </summary>
/// <param name="szsql">查询sql语句</param>
/// <param name="sztabname">表名称</param>
/// <returns>已经被填充的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>
/// 通过查询语句 创建dataset对象,返回的对象用于执行插入操作
/// </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>
/// 通过查询语句 创建dataset对象,返回的对象用于执行更新操作
/// </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>
/// 处理数据插入的更新事件
/// </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>
/// 在插入数据后获取新数据行中自增字段的值,目前只能支持一个自增字段
/// </summary>
public int32 dbidentity {get{return m_idbidentity;} }
/// <summary>
/// 数据库连接字符串,保存在web.config文件中 <appsettings>节
/// </summary>
public string dbstring {get{return system.configuration.configurationsettings.appsettings["dbstr"];}}

//------------公共变量
/// <summary>
/// 数据库连接
/// </summary>
public oledbconnection m_dbconn;
/// <summary>
/// 查询adapter
/// </summary>
public oledbdataadapter m_dbadapter;
public const string m_szrooturl ="/copathway/todo/";

//---------- 私有变量
/// <summary>
/// 保存数据库插入是自增字段的值
/// </summary>
protected int32 m_idbidentity =-1;
protected bool m_fautodelconn = true;
}
}  


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表