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?

解决方案 »

  1.   

    并发操作数据库,这种现象很正常
    针对这种类型的SQL可以考虑在程序一级加锁,只允许一个并发
      

  2.   

    我那个就算并发也不会有问题吧,那句insert本身已经有能力辨别数据状态了
      

  3.   

    SQL语句的执行不是原子的。
    比如设TableA中有一个x不存在于TableB中,有两个任务A,B同时执行,A能select到x,B也可能select到x,所以A,B都有可能将x插入到TableB中。
    当然,你也可以建立unique类型的索引,执行失败的会报异常。只是我认为,这条SQL最好是限制并发。
      

  4.   

    我是没太理解啊
    我认为我用insert into table select……的办法是把查询和插入都在数据库服务器端执行的
    我用程序是干预不到的,所以才这样使用,防止重复插入如果我用程序先select 数据到object ,再insert object到数据库,这样操作,我觉得可以从程序这里控制可以给我个简单的例子说一下从程序这里限制并发的方法吗?也许可以帮助我理解你的意思
      

  5.   

    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)
      

  6.   

    当两个相同并且全都null,这能实现判断两个都是真正有意义的相同业务数据的逻辑吗?
      

  7.   

    汗!逻辑没问题,只是一般认为exists优于left join
      

  8.   

    如果数据源有重复,是不是应该select distinct(ID)
      

  9.   

    不明白,请楼上的大神把字拆分开好吗?语文没学好,连在一起读不懂了……见笑我也想用not exist呢,这个我跟你的观点一致(原来的sql不是我写的撒,我还觉得他挺有才的呢)不过我觉得他的写法没有错误啊,b。id is null不就说明了b表中没有这个数据吗?
      

  10.   

    我是菜鸟,顺便也想问下查的时候是查的A,B两表的信息,然后又插入到B表,会不会导致查找到得B表信息不断变化又不断再次插入B表?
      

  11.   

    程序控制就是用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();
      

  12.   

    你这个我不太理解,是锁表了吗?我可能不能修改你这里的代码那个菜鸟,left join是左连接嘛,就是左边的表全显示出来,如果右边的表有符合条件的就显示右边表的数据,不符合条件的也显示,不过是null与join的区别就是,join不会显示不符合条件的
      

  13.   

    不用事务的话,第一个insert语句执行的时候,自然就把表锁了,第二个insert语句不会执行
    等第一个执行完了,表B中就有了A的ID,再执行一次也不会插入数据了
    怀疑是A表中有重复ID