我用这种办法插入数据,为什么会出现重复的插入,插入时间相同或者相距十几毫秒

billsquall 2011-07-28 06:09:41
insert into tableB
select ID from tableA a left join tableB b on a.ID=b.ID where b.ID is null

我用这种办法插入数据,为什么会出现重复的插入,插入时间相同或者相距十几毫秒

这是个web项目,每次点击按钮都会自来来找表A中的ID,一旦表B没有,就插入到表B,为了防止出现重复,我也懒得做判断,就这样写了sql,难道我的sql有bug?
...全文
216 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
小赖赖 2011-08-05
  • 打赏
  • 举报
回复
不用事务的话,第一个insert语句执行的时候,自然就把表锁了,第二个insert语句不会执行
等第一个执行完了,表B中就有了A的ID,再执行一次也不会插入数据了
怀疑是A表中有重复ID
Q333111555 2011-08-05
  • 打赏
  • 举报
回复
这个需要高手来回答,一二般的人解决不了这事
showjim 2011-07-29
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 billsquall 的回复:]
我那个就算并发也不会有问题吧,那句insert本身已经有能力辨别数据状态了
[/Quote]
SQL语句的执行不是原子的。
比如设TableA中有一个x不存在于TableB中,有两个任务A,B同时执行,A能select到x,B也可能select到x,所以A,B都有可能将x插入到TableB中。
当然,你也可以建立unique类型的索引,执行失败的会报异常。只是我认为,这条SQL最好是限制并发。
billsquall 2011-07-29
  • 打赏
  • 举报
回复
我那个就算并发也不会有问题吧,那句insert本身已经有能力辨别数据状态了
showjim 2011-07-29
  • 打赏
  • 举报
回复
并发操作数据库,这种现象很正常
针对这种类型的SQL可以考虑在程序一级加锁,只允许一个并发
billsquall 2011-07-29
  • 打赏
  • 举报
回复
没人遇到过类似的问题吗?超级郁闷
billsquall 2011-07-29
  • 打赏
  • 举报
回复
菜鸟,我那语句执行一次只能找到一次数据来插入,下载再执行的时候,因为上次已经插入过了,所以不会再次找出来了,你是不是以为他会循环一直执行了?
billsquall 2011-07-29
  • 打赏
  • 举报
回复
你这个我不太理解,是锁表了吗?我可能不能修改你这里的代码

那个菜鸟,left join是左连接嘛,就是左边的表全显示出来,如果右边的表有符合条件的就显示右边表的数据,不符合条件的也显示,不过是null

与join的区别就是,join不会显示不符合条件的
showjim 2011-07-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 billsquall 的回复:]
我是没太理解啊
我认为我用insert into table select……的办法是把查询和插入都在数据库服务器端执行的
我用程序是干预不到的,所以才这样使用,防止重复插入

如果我用程序先select 数据到object ,再insert object到数据库,这样操作,我觉得可以从程序这里控制

可以给我个简单的例子说一下从程序这里限制并发的方法吗?也许可以帮助我理解你的意思
[/Quote]
程序控制就是用lock之类的锁限制并发,如果我自己写过一个类适用于这种情况的

using System;
using System.Threading;
using System.Reflection;

namespace showjim.sys.threading
{
public class singleCall
{
private Action Call;
private int IsCalling = 0;
private int IsNewCall = 0;
private readonly object CompleteLock;
public singleCall(Action call, bool isComplete)
{
Call = call;
if (isComplete) CompleteLock = new object();
}
public void call()
{
if (CompleteLock == null)
{
if (Interlocked.Exchange(ref IsCalling, 1) == 0)
{
try
{
Call();
}
catch (Exception error)
{
showjim.sys.exception.debug.writeDebug(MethodBase.GetCurrentMethod(), error);
}
finally { IsCalling = 0; }
}
}
else
{
Monitor.Enter(CompleteLock);
int isCalling = IsNewCall = IsCalling;
IsCalling = 1;
Monitor.Exit(CompleteLock);
if (isCalling == 0)
{
do
{
try
{
Call();
}
catch (Exception error)
{
showjim.sys.exception.debug.writeDebug(MethodBase.GetCurrentMethod(), error);
}
finally
{
Monitor.Enter(CompleteLock);
isCalling = IsCalling = IsNewCall;
IsNewCall = 0;
Monitor.Exit(CompleteLock);
}
}
while (isCalling != 0);
}
}
}
}
}

初始化一个实例

class test
{
private static void DoSql()
{
string sql = "insert into tableB select ID from tableA where not exists(select ID from tableB where ID=tableA.ID)";
//..执行SQL
}
public static showjim.sys.threading.singleCall doSql
static test()
{
doSql = new showjim.sys.threading.singleCall(DoSql, true);
}
}

外部调用
test.doSql.call();
chinnsyuutou 2011-07-29
  • 打赏
  • 举报
回复
我是菜鸟,顺便也想问下查的时候是查的A,B两表的信息,然后又插入到B表,会不会导致查找到得B表信息不断变化又不断再次插入B表?
billsquall 2011-07-29
  • 打赏
  • 举报
回复
我是说sp1234大神
billsquall 2011-07-29
  • 打赏
  • 举报
回复
不明白,请楼上的大神把字拆分开好吗?语文没学好,连在一起读不懂了……见笑

我也想用not exist呢,这个我跟你的观点一致(原来的sql不是我写的撒,我还觉得他挺有才的呢)

不过我觉得他的写法没有错误啊,b。id is null不就说明了b表中没有这个数据吗?
showjim 2011-07-29
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 billsquall 的回复:]
补充一下,因为我的数据源是有重复数据的,所以没办法从表的设计那里做唯一属性

只是我不想插入的数据有多余的重复
[/Quote]
如果数据源有重复,是不是应该select distinct(ID)
showjim 2011-07-29
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 sp1234 的回复:]
on a.ID=b.ID where b.ID is null

你还真是胆大包天,这种东西逻辑上怎么解释?




from tableA a where not exists(select * from tableB b where a.ID=b.ID)
[/Quote]
汗!逻辑没问题,只是一般认为exists优于left join
  • 打赏
  • 举报
回复
当两个相同并且全都null,这能实现判断两个都是真正有意义的相同业务数据的逻辑吗?
  • 打赏
  • 举报
回复
on a.ID=b.ID where b.ID is null

你还真是胆大包天,这种东西逻辑上怎么解释?




from tableA a where not exists(select * from tableB b where a.ID=b.ID)
billsquall 2011-07-29
  • 打赏
  • 举报
回复
补充一下,因为我的数据源是有重复数据的,所以没办法从表的设计那里做唯一属性

只是我不想插入的数据有多余的重复
billsquall 2011-07-29
  • 打赏
  • 举报
回复
我是没太理解啊
我认为我用insert into table select……的办法是把查询和插入都在数据库服务器端执行的
我用程序是干预不到的,所以才这样使用,防止重复插入

如果我用程序先select 数据到object ,再insert object到数据库,这样操作,我觉得可以从程序这里控制

可以给我个简单的例子说一下从程序这里限制并发的方法吗?也许可以帮助我理解你的意思
billsquall 2011-07-28
  • 打赏
  • 举报
回复
不是每次都重复……我测试的都没问题,实际使用就有问题
我试过连点这个按钮来重复激发事件,还是没重复
billsquall 2011-07-28
  • 打赏
  • 举报
回复
绝对没有
加载更多回复(1)

110,567

社区成员

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

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

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