问题是每当我在同时查询Windows时执行存储过程“ usp_Execute100K ”时,服务器无法找到记录并创建新记录,即使记录已经存在。您必须同时运行“usp_Execute100K”多个窗口以查看此问题。
我想要的是确保服务器每天只创建1条记录,如果记录确实存在,则只将“StatisticTotal”列更新为下一个数字。
教会这个问题。
以下是1个表和两个存储过程
统计/ 表名 /
usp_Statistic_InsertOrUpdate / 这将更新“StatisticTotal”列,或者如果记录不存在则插入 /
usp_Execute100K / *这将执行usp_Statistic_InsertOrUpdate 10万次* /
GO
/****** Object: StoredProcedure [dbo].[usp_Execute100K] Script Date: 09/07/2011 15:37:29 ******/
DROP PROCEDURE [dbo].[usp_Execute100K]
GO
/****** Object: StoredProcedure [dbo].[usp_Statistic_InsertOrUpdate] Script Date: 09/07/2011 15:37:29 ******/
DROP PROCEDURE [dbo].[usp_Statistic_InsertOrUpdate]
GO
/****** Object: Table [dbo].[Statistic] Script Date: 09/07/2011 15:37:28 ******/
DROP TABLE [dbo].[Statistic]
GO
/****** Object: Table [dbo].[Statistic] Script Date: 09/07/2011 15:37:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Statistic](
[StatisticID] [uniqueidentifier] NOT NULL,
[StatisticAccount] [uniqueidentifier] NOT NULL,
[StatisticTotal] [float] NOT NULL,
[StatisticCreatedDate] [datetime] NOT NULL,
[DebugDate] [datetime] NULL,
CONSTRAINT [PK_Statistics] PRIMARY KEY CLUSTERED
(
[StatisticID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: StoredProcedure [dbo].[usp_Statistic_InsertOrUpdate] Script Date: 09/07/2011 15:37:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_Statistic_InsertOrUpdate](
@StatisticAccount uniqueidentifier
)
AS
SET NOCOUNT OFF; --this can be turn on or off, it has no effects
DECLARE @NowDate date
SET @NowDate=CONVERT(datetime, CONVERT(char, GETDATE(), 106))--remove all time.
--UPDATE ONLY IF IT HAS THE SAME DATE
UPDATE TOP (1) Statistic SET StatisticTotal =StatisticTotal+1 WHERE (StatisticAccount=@StatisticAccount AND StatisticCreatedDate = @NowDate)
if @@ROWCOUNT=0--If the above statement return no effects then create a new record
BEGIN
INSERT TOP (1)INTO Statistic(StatisticID, StatisticAccount, StatisticTotal, StatisticCreatedDate,DebugDate) VALUES (NEWID(),@StatisticAccount,1,@NowDate,@NowDate)
END
GO
/****** Object: StoredProcedure [dbo].[usp_Execute100K] Script Date: 09/07/2011 15:37:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_Execute100K]
AS
SET NOCOUNT OFF; --this can be turn on or off, it has no effects
declare @current float
set @current=0
while (@current <100000)
begin
--INSERT THIS STATEMENT for 100 thousand times
exec usp_Statistic_InsertOrUpdate'4c34eea5-fe17-4b11-8e06-0039577e7421'
set @current = @current + 1
end
GO
答案 0 :(得分:1)
1)在Statistic.StatisticAccount + Statistic.StatisticCreatedDate
上创建一个唯一索引,或仅在Statistic.StatisticCreatedDate
创建您的业务规则所指示的内容。
2)用你的INSERT包装:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
END CATCH
它只会忽略/丢弃失败的重复插入所产生的错误。
答案 1 :(得分:1)
您是否考虑过在事务中包装UPDATE / INSERT组合?虽然约束和TRY / CATCH肯定会阻止第二行,但它也会丢弃该尝试。如果你把它包装在一个事务中,并使用TABLOCK(我假设你可能会对这个表进行大量的写操作,但是没有大量的读操作),你会稍微妨碍并发性,但你可以更好地确保一个用户只能看到之后表的状态,其他用户完成了它。我可以原样可靠地获得两行,但是当我使用它时我无法获得两行:
ALTER PROCEDURE [dbo].[usp_Statistic_InsertOrUpdate]
@StatisticAccount UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON; -- this should always be on
DECLARE @NowDate DATE = CURRENT_TIMESTAMP;
-- by definition, you don't need to convert to remove time from date
BEGIN TRANSACTION;
--UPDATE ONLY IF IT HAS THE SAME DATE
UPDATE dbo.Statistic WITH (TABLOCK)
SET StatisticTotal += 1
WHERE StatisticAccount = @StatisticAccount
AND StatisticCreatedDate = @NowDate;
IF @@ROWCOUNT = 0
-- If the above statement return no effects then create a new record
BEGIN
INSERT dbo.Statistic
(
StatisticID,
StatisticAccount,
StatisticTotal,
StatisticCreatedDate,
DebugDate
)
SELECT
NEWID(),
@StatisticAccount,
1,
@NowDate,
@NowDate;
END
COMMIT TRANSACTION;
END
GO
错误捕获,回滚,约束等。我将作为练习离开。