2012-05-11 3 views
2

У меня возникли проблемы с вставкой строк в базу данных SQL. Я хочу превратить массив объектов в таблицу SQL в javascript.Асинхронный ввод SQL в цикле

Следующий код добавляет только первый объект массива. Я пробовал все, что мог найти в stackoverflow и в другом месте, и не могу заставить его работать.

Любая помощь будет оценена по достоинству. Благодарю.

 for (var i = 0; i < arr.length; i++) { 
      db.save({key:i+"", value:arr[i]}, function(e){ 

      }); 
     } 

UPDATE 1: Я изменил его mathec примера М. и сузил проблему немного.

Количество вставленных строк зависит от размера вставляемого объекта. Таким образом, это имеет какое-то отношение к времени, которое требуется для обработки каждого объекта.

Как решить эту проблему? Благодарю.

Update 2:

Я принял предложение Роберта Янга ниже и включен автономный пример.

В приведенном ниже примере вставляются только первые 5 элементов. Если я удаляю часть текста слова в тестовом ключе, поэтому он только говорит «слово» один раз, затем вставляется 10 элементов. Так что теперь я уверен, что это имеет какое-то отношение к времени, которое требуется для обработки каждого объекта.

<html> 
    <head> 
     <script src="jquery.js"></script> 
     <script src="lawnchair.js"></script> 
     <script type='text/javascript'> 


      var db = ""; 
      var arr = []; 

      arr.push({name:"a1", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a2", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a3", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a4", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a5", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a6", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a7", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a8", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a9", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a10", test:"word word word word word word word word word word word word word word "}); 
      arr.push({name:"a11", test:"word word word word word word word word word word word word word word "}); 

      $(function() { 
       db = new Lawnchair({table:'t50'}, function(e){ 
        for (i = 0; i < arr.length; i++) { 
         (function(i) { 
          add_row(i); 
         }(i)); 
        } 
       }); 
      }); 

      function add_row(i) { 
       db.save({key:i+"", value:arr[i]}, function(e){ 

       }); 
      } 

     </script> 
    </head> 
    <body> 

    </body> 
</html> 

UPDATE 3: Я использовал предложенный код Роберта и придумал, после чего работал с тремя маленькими элементами. Поэтому я изменил первый элемент, сделав его больше, чем другие, чтобы проверить его. Первый элемент не был добавлен, а последние два были. Есть ли ограничение по времени для обработки массива?

<html> 
    <head> 
     <script src="jquery.js"></script> 
     <script src="lawnchair.js"></script> 
     <script type='text/javascript'> 

      var arr = []; 
      var db = ""; 

      $(function() { 
       db = new Lawnchair({table:'t51'}, function(e){ 
        arr=[{key:"k1", value:"v1. Because the contents of this element are larger than the others it will not be added for some reason. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. "} 
        ,{key:"k2", value:"v2"} 
        ,{key:"k3", value:"v3"}] 

        db.batch(arr, function() { 
         db.all(function (recs) { for (r in recs) {console.log(recs[r].key +"| "+ recs[r].value) } }); 
        }); 
       }); 

      }); 

     </script> 
    </head> 
    <body> 
    </body> 
</html> 
+0

Я не вижу проблем с первым фрагментом кода, который вы отправили, за исключением того, что аргумент обратного вызова не нужен, если вы его не используете. Кажется, что-то странное происходит. Не могли бы вы опубликовать [короткий, самодостаточный пример] (http://sscce.org/) проблемы? –

+0

Привет, Роберт, я добавил полный пример, который вы предложили. Есть идеи? Благодарю. – user1389968

ответ

1

Во-первых, поскольку это постоянное хранилище, если вы запускаете это снова и снова, вы можете получать разные результаты каждый раз, потому что вы не инициализируете постоянное хранилище. Возможно, было бы неплохо добавить db.nuke(), чтобы убедиться, что вы начинаете с чистого листа, по крайней мере, до тех пор, пока не найдете какие-либо ошибки.

Главное знать о асинхронном хранении - это то, что функция возвращает не означает, что данные на самом деле хранятся. Так что, если вы запустите

db = new Lawnchair(function(db){ 
    db.save({key:"value"}) 
    db.get("foo", function (rec) { console.log(rec.value) }); 
}); 

он может или не может работать, потому что, когда вы звоните db.get, значение может или не может быть сохранена.

Для этого мы должны быть уверены, что это значение сохраняется до вызова db.get. Способ сделать это с помощью обратных вызовов - если вы передадите два аргумента в db.save, тогда он вызовет второй аргумент после сохранения значения. Таким образом,

db = new Lawnchair(function(db){ 
    db.save({key:"foo", value:"bar"}, function() { 
     db.get("foo", function (rec) { console.log(rec.value) }); 
    }); 
}); 

работает нормально.

Это становится трудно, если вы пытаетесь сохранить несколько значений, потому что вы хотите быть уверенным, что все они сохранены. К счастью, есть функция для этого, batch:

db = new Lawnchair(function(db){ 
    arr=[{key:"k1", value:"v1"},{key:"k2", value:"v2"},{key:"k3", value:"v3"}]; 
    db.batch(arr, function() { 
     db.all(function (recs) { for (r in recs) {console.log(recs[r].key) } }); 
    }); 
}); 

должен вывести

k1 
k2 
k3 

Попробуйте его и посмотреть, что происходит.

+0

Привет, Роберт, я попробовал ваш пример и так же, как мой, он работает только с очень небольшим количеством данных. Если вы замените «k1» в вашем примере большим текстом (например, абзацем), добавятся только последние два элемента. – user1389968

+0

Еще одна интересная вещь: когда вы увеличиваете размер текста в ключе или значение в первом элементе, последние два элемента добавляются в базу данных, но console.debug никогда не вызывается. Это очень странная проблема. – user1389968

+0

Это может быть проблема, зависящая от браузера, потому что у меня не было таких проблем. Какой браузер (версия, ОС) и какой адаптер Lawnchair вы используете? Возможно, браузер, который вы используете, не позволит хранить большие объемы данных? –

2

Трудная ошибка, которую я сделал себе несколько раз :-). Если в цикле вызывается функция обратного вызова, она будет вызываться асинхронно. Таким образом, ваш цикл будет продолжать выполнять весь путь до конца. Способ решения этой проблемы состоит в том, чтобы сформировать замыкание вокруг текущего значения i, чтобы при выполнении функции обратного вызова он был привязан к правильному i. Нечто подобное:

function doSomething(i) { 
    console.log(i) 
} 

var i, len; 

for (i = 0; i < 10; i++) { 
    (function(i) { 
    doSomething(i); 
    }(i)); 
} 

Функция внутри цикла будет выполняться сразу, а значение я будет храниться в объеме.

+0

Привет, я просто попробовал это, и снова он добавляет только первую строку. – user1389968

+0

Вам нужно ограничить возможности на этом этапе. Возможно, попробуйте записать значение массива, чтобы убедиться, что итерация работает. Затем, как только это подтвердится, проверьте журнал db, чтобы убедиться, что строка почему-то не отклоняется. – cmather

+0

Привет, Mathec, я сузил проблему. Чем больше объект, тем меньше вставок. Так что, если что-то связано со временем, которое требуется для обработки объекта. Но не могу понять, что. – user1389968

0

Трудно сузить решение проблемы, потому что мы не знаем, как вы сохраняете данные в БД, возможно, запрос AJAX ?, но я думаю, что проблема заключается в полной логике сохранения каждой строки из асинхронного массива, поскольку код не дожидается сохранения одной строки для запуска другой, поэтому происходит какое-то состояние гонки, а некоторые строки сохраняются в одном и том же «id» (поле автоинкремента), и это объясняет, почему некоторые строки сохраняются.

Мое предложение отправляет весь массив на сервер, а затем вы сохраняете каждую строку.

Конечно, вы могли бы сделать для каждой строки, сначала заблокировать идентификатор, а затем сохранить данные, но это плохая идея, потому что вам нужна обратная связь с сервером и БД для каждой строки, удваивая количество запросов к сервер.

Надеюсь, это поможет!

P.D.+1 для ответа @mathec для указания переменной цикла с обратным вызовом!

+0

Привет, Хуан, его хранят локально, поэтому нет необходимости беспокоиться о его отправке на сервер. Я попытаюсь проверить вашу гипотезу ID, но даже когда я просто добавлю одну немного большую строку (просто абзац текста в ключ) сам по себе, ничего не добавляется. Поэтому я думаю, что это связано с размером элемента. – user1389968

Смежные вопросы