当数据量达到每秒10条的时侯,数据库开始出现了很麻烦的问题

伊凡yifan 2008-03-09 06:43:38
M_MESSAGE是数据写入表
P_MESSAGE是数据处理结果表

A\B\C\D程序对M_MESSAGE进行操作(VC6.0程序构架)
最后的结果写入p_MESSAGE表


多个程序访问M_MESSAGE表

A进程负责往M_MESSAGE表里写数据(目前还无法得知是否全部成功写入)

-----------现在A进程达到了每秒10条的速度

B、C、D程序顺序对表进行查询、UPDATE工作


B程序调用DBO.getnext_msg对表进行查询,处理过程详看存储过程
C程序每隔一秒调用存储过程对P_MESSAGE进行扫描查看是否有需要处理的数据,如果有就连续处理,处理完去更新M_MESSAGE表里的状态字段。


当达到每秒多条的时侯

出现A、B两个新记录在瞬间入了M_MESSAGE表,程序进程处理结果先处理了B,而没有处理A,把B处理了2次,A就没有处理了。

D进程最后进行UPDATE工作的时侯,加了检测UPDATE是否成功还使用了获取SQL SERVER 2000处理RESULT的信息来
判断是否UPDATE成功

当A进程达到1秒十条的时侯,出现在这种棘手的问题

附存储过程:


CREATE PROCEDURE dbo.getnext_msg
@MaxProcessTime INT,
@MaxFailureCount INT

AS

DECLARE @NextMsg INT

SET @NextMsg = 0


SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION

SELECT TOP 1
@NextMsg=MO_MSG_NO

FROM M_MESSAGE
WHERE IS_VALID = 1 and
(PROCESS_STATUS = 1 or
(PROCESS_STATUS = 2 and DATEADD(second,@MaxProcessTime,PROCESS_DATE)<GETDATE()) or
(PROCESS_STATUS = 4 and FAILURE_COUNT<@MaxFailureCount))
ORDER BY MO_MSG_NO DESC

IF @NextMsg = 0
BEGIN
ROLLBACK TRANSACTION
RETURN 0
END
ELSE
BEGIN
UPDATE M_MESSAGE
SET PROCESS_STATUS = 2, PROCESS_DATE=GETDATE()
WHERE MO_MSG_NO = @NextMsg
END

COMMIT TRANSACTION
RETURN @NextMsg

GO

===========

CREATE PROCEDURE DBO.ServerNextMsg
@MaxProcessTime INT,
@MaxCheckTime INT
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION


declare @NextMsg as int

declare @service_id as varchar(10)
declare @src_id as varchar(15)
declare @dest_id as varchar(30)
select TOP 1 @NextMsg = P_MESSAGE.MSG_NO, @service_id = source_msg.service_id ,@src_id =P_MESSAGE.send_id from P_MESSAGE inner
join source_msg on P_MESSAGE.source_msg_id = source_msg.source_msg_id
where ((P_MESSAGE.PROCESS_STATUS = 1 or (P_MESSAGE.PROCESS_STATUS = 2 and DATEADD(second,@MaxProcessTime,P_MESSAGE.PROCESS_DATE)<GETDATE()))
and ( DATEADD(second,@MaxCheckTime,P_MESSAGE.CREATE_DATE)<GETDATE() )
and P_MESSAGE.IS_VALID = 1) and (source_msg.S_ID = '8983') ORDER by MSG_NO DESC


IF @NextMsg = 0
BEGIN
ROLLBACK TRANSACTION
RETURN -1
END
--ELSE IF @service_id not like 'BZ' and @service_id not like '269117' and @service_id not like '269115' and @service_id not like '269106' and @service_id not like '269107' and @service_id not like '269108' and @service_id not like '269118' and @NextMsg <> 0
ELSE IF @NextMsg <> 0 and @service_id not like 'BZ'
BEGIN

SELECT TOP 1 @dest_id = dest_id from m_message where m_message.src_id = @src_id and m_message.service_id = @service_id and m_message.process_status<>5 order by process_date desc


IF @dest_id is null OR @dest_id = ''
begin
ROLLBACK TRANSACTION
RETURN -2
end
else
begin
UPDATE P_MESSAGE
SET PROCESS_STATUS = 2, PROCESS_DATE=GETDATE()
WHERE MSG_NO = @NextMsg

--UPDATE m_message
--SET PROCESS_DATE=GETDATE(),MSG_NO = @NextMsg
--WHERE dest_id = @dest_id
end

END
ELSE
BEGIN


UPDATE P_MESSAGE
SET PROCESS_STATUS = 2, PROCESS_DATE=GETDATE()
WHERE MSG_NO = @NextMsg

END

COMMIT TRANSACTION

RETURN @NextMsg
GO


...全文
132 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
nzperfect 2008-03-10
  • 打赏
  • 举报
回复

智商有限,这么长,看不懂啊,能不能精简点呢
山之魂2 2008-03-10
  • 打赏
  • 举报
回复
楼上的头像伤眼睛^^^^^
w2jc 2008-03-10
  • 打赏
  • 举报
回复
LZ的BCD程序是否对每条记录都顺序作处理?

如果是这样的话,是否可以为每条记录加个标志字段?

程序B完成之后,做标识'B',
程序C就只需要找有标识'B'的记录接着后面的处理,处理完之后把标志改为'C',
如此类推...

-狙击手- 2008-03-09
  • 打赏
  • 举报
回复
有点乱,看的不太懂,
dawugui 2008-03-09
  • 打赏
  • 举报
回复
锁定记录,只允许单用户修改的例子

create table #锁表(编号 int)

--代码:
if exists(select 1 from 编号='你的编号')
return

insert #锁表 values('你的编号')

.....你处理的代码

delete #锁表 where 编号='你的编号'
--------------------------------------
--为了防止死锁,建议加时间:

create table #锁表(编号 int,时间 datetime)

--代码:
if exists(select 1 from 编号='你的编号' and datediff(ss,时间,getdate())<5 --如果锁的时候超过5秒,则是处理超时
)
return

delete from #锁表
insert #锁表 values('你的编号',getdate())

.....你处理的代码

delete #锁表 where 编号='你的编号'
---------------------------------------
--锁定记录,只允许单用户修改的例子:

--创建测试环境
--创建测试表--部门表
create table 部门(departmentid int,name varchar(10))

--记录锁定表
create table lock(departmentid int,dt datetime)

go
--因为函数中不可以用getdate,所以用个视图,得到当前时间
create view v_getdate as select dt=getdate()
go
--创建自定义函数,判断记录是否锁定
create function f_chk(@departmentid int)
returns bit
as
begin
declare @re bit,@dt datetime
select @dt=dt from v_getdate
if exists(select 1 from lock where departmentid=@departmentid
and datediff(ss,dt,@dt)<5)
set @re=1
else
set @re=0
return(@re)
end
go

--数据处理测试
if dbo.f_chk(3)=1
print '记录被锁定'
else
begin
begin tran
insert into lock values(3,getdate())
update 部门 set name='A' where departmentid=3
delete from lock where departmentid=3
commit tran
end

--删除测试环境
drop table 部门
drop view v_getdate
drop function f_chk
dawugui 2008-03-09
  • 打赏
  • 举报
回复
1 如何锁一个表的某一行
/*
测试环境:windows 2K server + Mssql 2000
所有功能都进行测试过,并有相应的结果集,如果有什么疑义在论坛跟帖
关于版权的说明:部分资料来自互联网,如有不当请联系版主,版主会在第一时间处理。
功能:sql遍历文件夹下的文本文件名,当然你修改部分代码后可以完成各种文件的列表。
*/


A 连接中执行

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

begin tran

select * from tablename with (rowlock) where id=3

waitfor delay '00:00:05'

commit tran

B连接中如果执行

update tablename set colname='10' where id=3 --则要等待5秒

update tablename set colname='10' where id<>3 --可立即执行

2 锁定数据库的一个表

SELECT * FROM table WITH (HOLDLOCK)


注意: 锁定数据库的一个表的区别

SELECT * FROM table WITH (HOLDLOCK)
其他事务可以读取表,但不能更新删除

SELECT * FROM table WITH (TABLOCKX)
其他事务不能读取表,更新和删除
dawugui 2008-03-09
  • 打赏
  • 举报
回复
看着都够麻烦的.

建议采取锁来处理.
伊凡yifan 2008-03-09
  • 打赏
  • 举报
回复
D进程最后进行UPDATE工作的时侯,加了检测UPDATE是否成功还使用了获取SQL SERVER 2000处理RESULT的信息来
判断是否UPDATE成功 最头痛的是UPDATE明明没有成功,而SQL SERVER 居然返回RESULT处理 成功影响了一条

附VC源代码:

if(g_DBConnect.GetRecordsAffected()<=0),如果<=0,失败

34,590

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧