高并发 防止重复数据

w87875251l 2018-01-10 03:48:23

ALTER proc [dbo].[submitVote]
(
@WorkId int,
@Name nvarchar(200),
@ret int output
)
as
if(select count(*) from WxMyVotes where WxWorkId=@WorkId and UserName=@Name and CONVERT(varchar(100), AddDate, 23)=CONVERT(varchar(100), GETDATE(), 23))=1
begin
set @ret=0
return
end

begin tran t1
declare @errorSum int
set @errorSum=0

insert into WxMyVotes(IsDelete, WxWorkId, UserName, AddDate) values(0, @WorkId, @Name, GETDATE())
set @errorSum=@@ERROR+@errorSum

update WxWorks set VoteCount=VoteCount+1 where Id=@WorkId
set @errorSum=@@ERROR+@errorSum
if @errorSum=0
begin
set @ret=1
commit tran t1
end
else
begin
set @ret=2
rollback tran
end



GO


一个简单的投票 ,当并发量大时 ,WxMyVotes 表 会出现重复数据(同一WxWorkId,UserName,和同一天) 也就是
if(select count(*) from WxMyVotes where WxWorkId=@WorkId and UserName=@Name and CONVERT(varchar(100), AddDate, 23)=CONVERT(varchar(100), GETDATE(), 23))=1 这个限制并没限制住

如何解决
...全文
788 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
OwenZeng_DBA 2018-01-11
  • 打赏
  • 举报
回复
引用 8 楼 w87875251l 的回复:
[quote=引用 7 楼 zjcxc 的回复:] [quote=引用 5 楼 w87875251l 的回复:] 唯一建约束 怎么放到多个 字段上WxWorkId UserName AddDate(和日期判断2018-01-10 不和时间判断) ??而且 而且 AddDate 是存的完整日期 '2017-11-21 05:00:12.5474774' 我要和当天判断
加个计算列,只包含日期信息,然后就可以用唯一索引了
alter table 表名 add 日期计算列 as convert(char(10), AddDate, 120);
create iunique index 索引名 on 表名(WxWorkId , UserNam,  日期计算列);
[/quote] 这个表已经有自增主键Id 再建唯一索引没影响吧[/quote] 可以的
w87875251l 2018-01-11
  • 打赏
  • 举报
回复
引用 7 楼 zjcxc 的回复:
[quote=引用 5 楼 w87875251l 的回复:] 唯一建约束 怎么放到多个 字段上WxWorkId UserName AddDate(和日期判断2018-01-10 不和时间判断) ??而且 而且 AddDate 是存的完整日期 '2017-11-21 05:00:12.5474774' 我要和当天判断
加个计算列,只包含日期信息,然后就可以用唯一索引了
alter table 表名 add 日期计算列 as convert(char(10), AddDate, 120);
create iunique index 索引名 on 表名(WxWorkId , UserNam,  日期计算列);
[/quote] 这个表已经有自增主键Id 再建唯一索引没影响吧
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
引用 5 楼 w87875251l 的回复:
唯一建约束 怎么放到多个 字段上WxWorkId UserName AddDate(和日期判断2018-01-10 不和时间判断) ??而且 而且 AddDate 是存的完整日期 '2017-11-21 05:00:12.5474774' 我要和当天判断
加个计算列,只包含日期信息,然后就可以用唯一索引了
alter table 表名 add 日期计算列 as convert(char(10), AddDate, 120);
create iunique index 索引名 on 表名(WxWorkId , UserNam,  日期计算列);
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
援藏唯一索引或约束 直接用语句意味着要通过加锁保证,而加锁的话,因为你要防止的是不存在时的并发,所以要锁住范围,在 SQL Server 中,最高隔离级别 SERIALIZABLE 才能锁住范围,这个时候并发性低,容易死锁
begin tran t1
 if(select count(*) from WxMyVotes with(updlock,holdlock) where WxWorkId=@WorkId and UserName=@Name and CONVERT(varchar(100), AddDate, 23)=CONVERT(varchar(100), GETDATE(), 23))=1
   begin 
     set @ret=0
     return
   end
   
--begin tran t1
declare @errorSum int
w87875251l 2018-01-11
  • 打赏
  • 举报
回复
唯一建约束 怎么放到多个 字段上WxWorkId UserName AddDate(和日期判断2018-01-10 不和时间判断) ??而且 而且 AddDate 是存的完整日期 '2017-11-21 05:00:12.5474774' 我要和当天判断
shoppo0505 2018-01-11
  • 打赏
  • 举报
回复
begin tran t1 这个放到if前面试试
OwenZeng_DBA 2018-01-10
  • 打赏
  • 举报
回复
引用 2 楼 w87875251l 的回复:
我的C#代码 代码是.net core 的


            ApplicationUser userInfo = await _userManager.GetUserAsync(HttpContext.User);

            ApplicationDbContext context = HttpContext.RequestServices.GetService<ApplicationDbContext>();
            DbConnection conn = context.Database.GetDbConnection();
            if (conn.State != System.Data.ConnectionState.Open)
            {
                conn.Open();
            }

            string str = "";
            DbCommand comm = conn.CreateCommand();
            comm.CommandType = CommandType.StoredProcedure;
            comm.CommandText = "submitVote";
            comm.Parameters.Add(new SqlParameter("@WorkId", workId));
            comm.Parameters.Add(new SqlParameter("@Name", userInfo.UserName));

            SqlParameter outputPara = new SqlParameter("@ret", SqlDbType.Int)
            {
                Direction = ParameterDirection.Output
            };
            comm.Parameters.Add(outputPara);
            comm.ExecuteNonQuery();

            str = outputPara.Value.ToString();

害怕重复可以考虑给表加个主键或者唯一建约束
w87875251l 2018-01-10
  • 打赏
  • 举报
回复
我的C#代码 代码是.net core 的


            ApplicationUser userInfo = await _userManager.GetUserAsync(HttpContext.User);

            ApplicationDbContext context = HttpContext.RequestServices.GetService<ApplicationDbContext>();
            DbConnection conn = context.Database.GetDbConnection();
            if (conn.State != System.Data.ConnectionState.Open)
            {
                conn.Open();
            }

            string str = "";
            DbCommand comm = conn.CreateCommand();
            comm.CommandType = CommandType.StoredProcedure;
            comm.CommandText = "submitVote";
            comm.Parameters.Add(new SqlParameter("@WorkId", workId));
            comm.Parameters.Add(new SqlParameter("@Name", userInfo.UserName));

            SqlParameter outputPara = new SqlParameter("@ret", SqlDbType.Int)
            {
                Direction = ParameterDirection.Output
            };
            comm.Parameters.Add(outputPara);
            comm.ExecuteNonQuery();

            str = outputPara.Value.ToString();

吉普赛的歌 2018-01-10
  • 打赏
  • 举报
回复
改成这样试下:
IF EXISTS(
		   SELECT 1
		   FROM   WxMyVotes
		   WHERE  WxWorkId         = @WorkId
				  AND UserName     = @Name
				  AND AddDate>convert(char(10),GETDATE(),120)
	)
	BEGIN
		SET @ret = 0
		RETURN
	END

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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