你看看我这把//-------------------------------
//功能 : 得到作业编码
//函数名: GetTaskCode
//参数 : LPCTSTR lpPlanClass, 计划类型名
// LPCTSTR lpCnnStr, 数据库连接串
// CString &cszCode 返回计划类型编码
//返回值:
//日期 :2003-11-22 10:40:47
//--------------------------------
long GetTaskCode(LPCTSTR lpPlanClass, LPCTSTR lpCnnStr, CString &cszCode)
{
CDbFuc dbf;
dbf.Init();
CString cszSvrName, cszSvrPW;
GetDfSvr(cszSvrName, cszSvrPW);
dbf.ConnectSvr(lpCnnStr);
CString cszSql;
cszSql.Format(" select * from tepcplan..planlist where planname = '%s' ",
lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
if(dbf.m_pRecordset->adoEOF)
return -1;
int i = 3;
for(;i < 0; i--)
{
cszSql.Format(" use tepcplan select * from planlist where planname = '%s and tepc_inuseing = 0' ",
lpPlanClass );
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} if(dbf.m_pRecordset->adoEOF)
{
::Sleep(100);
continue;
}
else break;
}
if(i < 0) return -1;
cszSql.Format(" update tepcplan..planlist set TaskCodeBase = TaskCodeBase + 1, tepc_inusing = 1 where planname = '%s' ", lpPlanClass);
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} cszSql.Format(" select taskcodebase,wybm from tepcplan..planlist where planname = '%s' ",
lpPlanClass);
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} long lValue;
try
{
if(dbf.m_pRecordset->adoEOF)
{
return -1;
}
_variant_t viValue;
viValue = dbf.m_pRecordset->GetCollect("taskcodebase");
lValue = viValue.lVal;
viValue = dbf.m_pRecordset->GetCollect("wybm");
cszCode = ::_com_util::ConvertBSTRToString(viValue.bstrVal);
}
catch(_com_error e)
{
AfxMessageBox(e.Description());
return -1;
} cszSql.Format(" update tepcplan..planlist set tepc_inusing = 0 where planname = '%s' ", lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
return lValue;
}CString GetFldName(CString cszFld)
{
for(int i = cszFld.GetLength() - 1; i >= 0; i--)
{
if(cszFld[i] == '.')
{
cszFld = cszFld.Right(cszFld.GetLength() - i - 1);
return cszFld;
}
}
return cszFld;
}
//功能 : 得到作业编码
//函数名: GetTaskCode
//参数 : LPCTSTR lpPlanClass, 计划类型名
// LPCTSTR lpCnnStr, 数据库连接串
// CString &cszCode 返回计划类型编码
//返回值:
//日期 :2003-11-22 10:40:47
//--------------------------------
long GetTaskCode(LPCTSTR lpPlanClass, LPCTSTR lpCnnStr, CString &cszCode)
{
CDbFuc dbf;
dbf.Init();
CString cszSvrName, cszSvrPW;
GetDfSvr(cszSvrName, cszSvrPW);
dbf.ConnectSvr(lpCnnStr);
CString cszSql;
cszSql.Format(" select * from tepcplan..planlist where planname = '%s' ",
lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
if(dbf.m_pRecordset->adoEOF)
return -1;
int i = 3;
for(;i < 0; i--)
{
cszSql.Format(" use tepcplan select * from planlist where planname = '%s and tepc_inuseing = 0' ",
lpPlanClass );
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} if(dbf.m_pRecordset->adoEOF)
{
::Sleep(100);
continue;
}
else break;
}
if(i < 0) return -1;
cszSql.Format(" update tepcplan..planlist set TaskCodeBase = TaskCodeBase + 1, tepc_inusing = 1 where planname = '%s' ", lpPlanClass);
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} cszSql.Format(" select taskcodebase,wybm from tepcplan..planlist where planname = '%s' ",
lpPlanClass);
if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} long lValue;
try
{
if(dbf.m_pRecordset->adoEOF)
{
return -1;
}
_variant_t viValue;
viValue = dbf.m_pRecordset->GetCollect("taskcodebase");
lValue = viValue.lVal;
viValue = dbf.m_pRecordset->GetCollect("wybm");
cszCode = ::_com_util::ConvertBSTRToString(viValue.bstrVal);
}
catch(_com_error e)
{
AfxMessageBox(e.Description());
return -1;
} cszSql.Format(" update tepcplan..planlist set tepc_inusing = 0 where planname = '%s' ", lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
return lValue;
}CString GetFldName(CString cszFld)
{
for(int i = cszFld.GetLength() - 1; i >= 0; i--)
{
if(cszFld[i] == '.')
{
cszFld = cszFld.Right(cszFld.GetLength() - i - 1);
return cszFld;
}
}
return cszFld;
}
这是我以前用的一个,你可以参考一下:
CREATE TRIGGER PayWastCode ON PayWaste
INSTEAD OF INSERT
AS
DECLARE @PayID VARCHAR(12)
DECLARE @ret_str VARCHAR(20)
DECLARE @curtime datetime declare @yval varchar(4)
declare @mval varchar(2)
declare @dval varchar(2)SET @curtime = GETDATE()
set @yval = cast(YEAR(@curtime) as varchar(4))
set @mval = cast(MONTH(@curtime) as varchar(2))
set @dval = cast(DAY(@curtime) as varchar(2))Execute master.dbo.xp_sprintf @ret_str output,
'%04s%02s%02s000',@yval,@mval,@dval
SET @PayID = NULL
SELECT @PayID = PayID FROM paywaste
WHERE PayID >= @ret_str
If @PayID is null SET @PayID= @ret_str
Else
Set @PayID = cast(@PayID as bigint)+1
Insert into paywaste SELECT @PayID,
TeleCode,UserName,DeptCode,DeptName,PayKind,TotalMoney,PayMoney,DelayMoney,BeginDate,
EndDate,PayDate,RelPayId,PayClass,PrnNum,OptId,StationId
FROM inserted
假设你要插入一条记录,那么你就取最大编号:不是N+1,然后进行插入
如果在你取编号后,插入记录前,又有另一个用户要插入记录,那很显然,因为你的记录还未插
入,那另一个用户取得的编号仍然是N+1,和你的一样,这样就导致了编号重复.
只锁最大记录的情况:
假设你要插入一条记录,那么你就取最大编号:不是N+1,然后进行插入
如果在你取编号后,插入记录前,又有另一个用户修改记录,他将某条记录修改成了N+!
那结果和上面一样,导致了编号重复.
锁整个表的情况:
因为你在取编号时,锁住了整个表,那很显然,就相当于你独占了整个表,此时,可以避免编号重复,但另一个后果是,所有的用户都必须等你释放了锁后,才能使用,包括只是读取表的用户,如果迸发用户多的话,很显然严重影响效率.
create function f_newid()
returns char(7) --编号位数固定,用char的检索效率高于varchar
as
begin
declare @re char(7)
select @re=max(BHID) from 表
return(
case when @re is null then 'BH00001'
else 'BH'+right('0000'+cast(cast(right(@re,5) as int)+1 as varchar),5)
end)
end
go--测试的表,表名与函数中的表名对应
create table 表(
BHID char(7) default dbo.f_newid() --设置默认值,自动生成编号
primary key, --设置成主键,防止编号冲突
-- constraint UNIQUE_BHID_表 unique, --如果用唯一约束,则删除上面的主键约束语句,改用此句
txt1 varchar(10),
txt2 varchar(10),
num float)
go/*--插入数据时,就可以不理会编号字段,直接用这样的语句
多用户同时插入时,如果编号重复,就会有错误发生
此时,前台程序拦截错误,如果是违反约束的错误
只需要重新执行插入的语句即可,此时的编号会自动再重新生成
而重新执行插入语句也很方便,因为根本就不需要改语句
--*/
insert 表(txt1,txt2,num) values('aa','bb',1)go
--删除测试
drop table 表
drop function f_newid
约束会阻止此插入操作前台程序拦截错误,客户重新执行插入的语句,有可能造成某客户长期等待危险如果用表级锁,那客户的等待时间更长,而且影响正常的读表操作.
已经解决了,特别感谢zjcxc(邹建)为我提供了一个很好的思路。
项目组提出的提供几种方式,并比较优略.
我的报告大约这样写的:1.只使用主键约束(主键上没有聚集索引)
使用事务插入,如果事务失败(算号重复),则算新号,重新插入.
好处实现容易,简单.坏处有的进程会滞留很长时间,维护索引需要时间
2.除了主键,加表锁
好处不会出现算号重复的情况,缺点进程排队等待,耗时长,并且影响其他正常的读取.3.放弃算号使用,自增长,并在其上建聚集索引,算号在取出时,临时依据自增长号计算
处理非常简单,不用考虑事务和锁的处理.
缺点,在取出时,还要浪费一些时间计算号,多进程插入,存在热点问题,(因为SQLSERVER 会锁住物理的数据页,其他插入等待)4.建立发号表,和发号存储过程,进行发号.
字段: 模块名 前缀 后缀 序列号 ,步长,补位符,补位长
模块名 前缀 后缀 建主建并聚集索引 发号存储过程 算号,返回算号,同时用算号更新序列号
好处:算号速度快,不会发生重复,不容易出现滞留,算号的算法可以进行维护
缺点:多了代码,不能完全消除滞留现象
我再问一句,用你的办法用insert into的方法插入,怎么能得到最后插入的一条记录的编号呢?