Помогите оптимизировать код
Всем привет.
есть функция, которая отправляет данные на сервер из локальной Web SQL function SendPost() { db.transaction(function (tx) { tx.executeSql("SELECT keyNumber, itemNumber, curDate FROM items", [], function(tx, results) { if(results.rows.length > 0) { for(var i = 0; i < results.rows.length; i++) { var someArray = [results.rows.item(i).keyNumber, results.rows.item(i).itemNumber,results.rows.item(i).curDate]; addArray(someArray); } } }); }); function addArray(arr) { $.ajax({ url: 'http://www.test.ru/add_to_base.php', dataType: 'text', type: 'post', contentType: 'application/x-www-form-urlencoded', data: ({knb:arr[0], inb:arr[1], cdt:arr[2]}), success: function( data, textStatus, jQxhr ){ console.log(data); }, error: function( jqXhr, textStatus, errorThrown ){ if(jqXhr.status&&jqXhr.status==400){ alert("Ошибка!: " + jqXhr.responseText); } else if(jqXhr.status&&jqXhr.status==500){ alert("500 - ошибка подключения к серверу"); } else{ alert("Something went wrong"); } } }); } код работает, но есть вопросы: 1) как лучше оптимизировать, что бы не вызывать каждый раз функцию addArray(). или это нормально - на каждую запись отправлять POST? 2) в случае ошибки, как остановить выполнение кода? например при ошибке 500. Так как цикл уже запустился, то прервать работу SendPost() уже не получается :( буду рад любым советам |
Цитата:
PS. Ваш код означает, что клиент валит сервер своими запросами, от этого 500. Если каждую запись отправлять отдельно, то делать это нужно только после того, как сервер ответит на предыдущий запрос. |
Цитата:
|
Удалить функцию addArray, перенеся Ajax запрос на место строк 7-11, передавая серверу результат запроса к БД как JSON.
На сервере декодировать и выполнить. |
Цитата:
|
Не знаю какой пример приводить, так как это связка клиент-сервер. Но коли сервер оперировал одной строкой данных, а теперь получит всю выборку, то серверный скрипт придется все равно править. Поэтому можно отослать как есть, и на сервере оперировать именами полей локальной SQL таблицы - keyNumber, itemNumber, curDate, а не knb, inb, cdt.
В этом случае: db.transaction(function (tx) { tx.executeSql("SELECT * FROM items", [], function(tx, results) { if(results.rows.length > 0) { $.ajax({ //... data: 'key='+JSON.stringify(results.rows), //... }) } }); }); На сервере вся выборка, это json_decode($_POST['key']). Если по каким-то причинам этого не желательно, то: db.transaction(function (tx) { tx.executeSql("SELECT * FROM items", [], function(tx, results) { if(results.rows.length > 0) { for(var i=0, rows=[]; i<results.rows.length; i++) rows.push({ knb:results.rows.item(i).keyNumber, inb:results.rows.item(i).itemNumber, cdt:results.rows.item(i).curDate }); $.ajax({ //... data: 'key='+JSON.stringify(rows), //... }) } }); }); Многое зависит от операций с данными на сервере. |
laimas, спасибо. буду пробовать.
На сервере строки пишутся в БД в том же виде |
Если сервер пишет в базу, то тем более выгоднее сразу все вставить, одним запросом многострочной вставкой. А для этого хватит и просто одних значений (без ключей), главное чтобы клиент передавал их в нужном порядке. На сервере эти данные приводятся к запросу:
INSERT INTO tbl (filed, filed, filed) VALUES (val, vall, val), (val, vall, val), (val, vall, val), ... с учетом соглашений и макс. размера пакетной записи. |
Цитата:
но сейчас на сервер приходит массив такого типа: (index):349 Array ( [key] => [{"knb":"111111111111","inb":"222222222222","cdt":"2018-01-29 17:20:27"},{"knb":"qqqqqqqqqqqq","inb":"666666666666","cdt":"2018-01-29 17:21:28"},{"knb":"qqqqqqqqqqqq","inb":"777777777777","cdt":"2018-01-29 17:21:28"}] )теперь нужно считать строки на сервере и записывать каждую? |
NSERT INTO tbl (field_name, field_name, field_name) VALUES (value, value, value) - это вставка в таблицу одной строки. Можно циклом обойти массив, вставляя таким образом отдельно строки. Но выгоднее сделать один запрос вставив сразу несколько строк, если БД это позволяет. Синтаксис запроса тот же самый, только перечислений вставляемых данных будет равно их числу, с указанием их через запятую:
NSERT INTO tbl (field_name, field_name, field_name) VALUES (value, value, value), (value, value, value), ... Но при такой записи нужно учитывать максимально разрешенный размер пакетной записи. В MySQL по умолчанию он равен 16 МБ. Если данных гарантированно меньше этого объема, то подготавливаем запрос и выполняем его. В противном случае данные разбиваются на несколько запросов для многострочной вставке. Можно узнать разрешенный размер пакетной записи запросом 'SHOW VARIABLES LIKE "max_allowed_packet"'. Запрос вернет размер в байтах. Из $_POST нужно еще получить данные: $data = json_decode($_POST['kye'], 1); А далее данные из массива $data подготовить для запроса учитывая, что данные должны быть обработаны и соответственно представлены (int или string). Если сервер использует оригинальное расширение MySQL, то придется все делать ручками. В случае если mysqli или PDO, то используя подстановки для подготовленного запроса, а "безопасность" запроса обеспечит сам SQL драйвер. |
Цитата:
for ($i = 0; $i < count($data); $i++){ $success = mysql_query("INSERT INTO .... VALUES ('".$data[$i]["knb"]."', '".$data[$i]["inb"] ..... записей будет около 3000 строк за раз. думаю это не так много |
Цитата:
|
Цитата:
я проверил, запросы выполняются не так долго, несколько секунд. Так что не пойму - что именно плохого? |
Цитата:
Ваш запрос не делает элементарного, экранирование данных. Но если это и будет сделано, то это будет означать только одно - текущий запрос исключает sql-инъекцию. Но данные помещенные в базу могут служить источником данных вложенных запросов впоследствии, а значит нужно будет всегда помнить об этом и производить их экранирование. Все потому, что вы данные не фильтруете, вас вообще не интересует действительно ли это ваши данные, соответствуют ли они типам ожидаемым. Контекст вашей темы, это оптимизация. А что такое по вашему оптимизация - красиво выполнить действия на клиенте? А на сервере как получится? Если СУБД не позволяет записать в базу набор данных в рамках одного запроса, это плохо, но придется выполнять массу запросов. Но если позволяет, то почему же вы не думаете об оптимизации? Я ведь показывал что нужно сделать, да даже если бы и не показал, вы, думая об оптимизации, просто обязаны изучить возможности СУБД, дабы сделать запись оптимальной. Это вы обязаны знать - http://fi2.php.net/manual/ru/security.database.php. Это очень желательно знать - http://fi2.php.net/manual/ru/book.filter.php. Это http://fi2.php.net/manual/ru/book.mysqli.php или это http://fi2.php.net/manual/ru/book.pdo.php нужно использовать вместо этого http://fi2.php.net/manual/ru/book.mysql.php. Используя оригинальное расширение MySQL, вы обязаны сами экранировать данные подставляемые в запрос функцией mysql_real_escape_string(). При этом ожидаемые данные типа integer можно приводить к данному типу, и при этом помещать их в кавычки совсем не требуется. Допустим, если в ключах knb и inb ожидаем integer, а в cdt строку, то данные первых двух ключей приводим к integer, а последнего экранируем функцией mysql_real_escape_string() и обрамляем кавычками. Подготовив таким образом данные для запроса, делаем запрос: if($data = json_decode($_POST['kye'])) { //каждое вложение $data при таком декодировании будет объектом //подготавливаем запрос $sql = 'INSERT INTO FROM table (...) VALUES ' . implode(',', array_map(function($v) { return '(' . (int)$v->kbn . ',' . (int)$v->inb . ',"' . mysql_real_escape_string($v->cdt) . '")'; }, $data)); //выполняем запрос mysql_query($sql); } При подготовке запроса можно не просто приводить данные к типу и экранировать, а производить их фильтрацию - если (int)$v->kbn или (int)$v->inb ноль, а это не должно быть, значит липовые данные, завершаем работу. Дату ли содержит $v->cdt или "Привет Федя!" ведь тоже не проблема проверить. То есть, либо if((int)$v->kbn) ..., либо используем класс Filter. А в mysqli и PDO все, кроме фильтрации в контексте "то ли пришло?", можно возложить на sql-драйвер, указав типы и используя подстановки. Драйвер подготовит запрос корректно экранируя и подставив данные в запрос. Запрос будет выглядеть как 'INSERT INTO FROM table (...) VALUES (?,?,?),(?,?,?),(?,?,?),...' На исполнение отдается этот запрос и массив данных - все вложенные массивы помещаются в один одномерный. Декодирование JSON при этом должно возвращать массив, указывая функции json_decode вторым параметром true/1. И почитайте о различиях разбора в РНР строковых значений помещенных в одинарные и двойные кавычки. |
laimas, все понял. Спасибо большое! Вы мне очень помогли.
|
Часовой пояс GMT +3, время: 00:40. |