.net高并发请求下实现SQL的有则更新无则添加。

game438951 2015-05-22 10:44:26
数据表中有个主键自增字段,还有一个唯一索引。
场景:每次增加数据时,都要查询数据表中唯一索引是否已经存在,如果不存在则插入数据,如果存在则更新除唯一索引和自增主键以外的字段。

我现在的做法,在客户端写了两条sql ,首先一条判断唯一所以是否存在 select count(*) from tablename where uniquecolumnkey='onekey' (请优化这条查询是否存在的语句)

再根据返回的结果写一条update或者Insert语句。。

遇到的问题:在高并发的情况下,会插入重复的唯一索引引发报错。

比如线程1查询唯一索引还不存在(时间点1),然后插入了一条数据(时间点2),
同事线程2查询唯一索引不存在(时间点3),然后插入了一条数据(时间点4)
由于 时间点1<时间点3<时间点2<时间点4 从而当线程2插入数据时引发报错,唯一索引不能重复插入数据


这种问题该怎么解决。。

是通过insert into
select
--

where
not exists
(select
--
from
--
where
--

)
写这样一条语句,(这条语句是否也会在高并发的时候出现问题??)还是弄一个事务比较好??
...全文
408 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
吉普赛的歌 2015-05-22
  • 打赏
  • 举报
回复
引用 7 楼 sp1234 的回复:
不要写 count(*) 统计,而应该写 exists 查询,只要判断是否存在记录就行了,不要统计记录数。并且t-sql会自动优化 exists 中的 select * 语句(并不返回任何字段),所以应该使用 select * from .....而不是某些人写的 select 1 from .....。 一个更新语句通常是这样的
if not exists(select * from [table] where name=@name)
     insert [table](id, name, cost) values (@id, @name, 1500) 
else 
    update [table] set name='xxx1' where name=@name
如果 insert、update 有多条记录,就使用begin....end语句块。
稍改一下: if not exists(select * from [table] with(nolock) where name=@name)
  • 打赏
  • 举报
回复
引用 5 楼 game438951 的回复:
引用 3 楼 Z65443344 的回复:
高并发最好是做存储过程
这样一个存储过程加事务该怎么写捏?
没有什么可见的意义,拿着通常“完全可以忽略的差别影响”来说的。
  • 打赏
  • 举报
回复
不要写 count(*) 统计,而应该写 exists 查询,只要判断是否存在记录就行了,不要统计记录数。并且t-sql会自动优化 exists 中的 select * 语句(并不返回任何字段),所以应该使用 select * from .....而不是某些人写的 select 1 from .....。 一个更新语句通常是这样的
if not exists(select * from [table] where name=@name)
     insert [table](id, name, cost) values (@id, @name, 1500) 
else 
    update [table] set name='xxx1' where name=@name
如果 insert、update 有多条记录,就使用begin....end语句块。
於黾 2015-05-22
  • 打赏
  • 举报
回复
存储过程是在数据库里定义的 调用存储过程,不需要再在代码中加事务.
game438951 2015-05-22
  • 打赏
  • 举报
回复
引用 3 楼 Z65443344 的回复:
高并发最好是做存储过程
这样一个存储过程加事务该怎么写捏?
那城 2015-05-22
  • 打赏
  • 举报
回复
放在存储过程中,用事务来控制
於黾 2015-05-22
  • 打赏
  • 举报
回复
高并发最好是做存储过程
  • 打赏
  • 举报
回复
select top 1 1 from tablename where uniquecolumnkey='onekey'
因为高并发,所以其实你可以直接Insert,然后通过catch的具体异常判断你是不是唯一性约束造成的,如果是的话,则执行update
software_artisan 2015-05-22
  • 打赏
  • 举报
回复
ExecuteNonQuery()方法不是返回受影响行数么,update的时候判断下返回值是否大于0,不大于0的话,执行insert语句就可以了。
编程有钱人了 2015-05-22
  • 打赏
  • 举报
回复
高并发就应该加锁,否则你后悔去吧
  • 打赏
  • 举报
回复
其实就算是有几百万条记录 --> 其实就算是库中有几百万条记录 如果遇到这种查询,我肯定是会首先检查是否对name创建有索引的,以保证只需要读取及少量的记录。这是一个前提。 如果没有索引,那么就算是查询一条记录也会去遍历上百万条记录,那么就算是写with nolock也快不了100倍(还是需要回到索引问题上)。
  • 打赏
  • 举报
回复
引用 9 楼 yenange 的回复:
[quote=引用 7 楼 sp1234 的回复:] 不要写 count(*) 统计,而应该写 exists 查询,只要判断是否存在记录就行了,不要统计记录数。并且t-sql会自动优化 exists 中的 select * 语句(并不返回任何字段),所以应该使用 select * from .....而不是某些人写的 select 1 from .....。 一个更新语句通常是这样的
if not exists(select * from [table] where name=@name)
     insert [table](id, name, cost) values (@id, @name, 1500) 
else 
    update [table] set name='xxx1' where name=@name
如果 insert、update 有多条记录,就使用begin....end语句块。
稍改一下: if not exists(select * from [table] with(nolock) where name=@name)[/quote] 这语句真实的目的不是查询返回大量数据,而是插入或者更改,因此它禁止其它数据库事务去update相同记录,也是可以的。最主要地是,它顶多lock一条记录。其实就算是有几百万条记录,测试下来我猜也看不出写何不写with nolock 的速度差别(可能不到0.1毫秒)。 如果是大的查询,那可能是需要写 with nolock 的。
  • 打赏
  • 举报
回复
主要是要分析具体的语句的执行过程。例如你发送给数据库系统的命令是一个事务还是多个事务?如果你的命令中包含多个事务,那么你就应该采用“显示事务”语句。sql server会将每一个命令都先进行编译,以后再次遇到相同(但是变量的值可以不同)的语句时就会执行编译结果。 数据库的所谓“更新一致性”是靠花费时间代价来得到的。数据库事务就是时间的杀手。如果你需要“多线程操作”时的数据一致性,在业务逻辑上不能容忍任何一种不一致性,那么就要使用数据库事务。 由于数据库操作本身就很费时间,所以其实没有什么特别的数据库编程的方式比常规方式更具有明确可见的优化意义。

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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