Лучшая альтернатива подготовленной инструкции при использовании SELECT SQLite? [Дубликат]

Ваш код разбит на две полностью отдельные части, серверную сторону и клиентскую сторону .

                    |
               ---------->
              HTTP request
                    |
+--------------+    |    +--------------+
|              |    |    |              |
|    browser   |    |    |  web  server |
| (JavaScript) |    |    |  (PHP etc.)  |
|              |    |    |              |
+--------------+    |    +--------------+
                    |
  client side       |      server side
                    |
               <----------
          HTML, CSS, JavaScript
                    |

Обе стороны общаются через HTTP-запросы и ответы. PHP выполняется на сервере и выводит код HTML и, возможно, JavaScript, который отправляется как ответ клиенту, где интерпретируется HTML, и выполняется JavaScript. Когда PHP завершит вывод ответа, сценарий закончится, и на сервере ничего не произойдет, пока не появится новый HTTP-запрос.

Пример кода выполняется следующим образом:


Шаг 1, PHP выполняет весь код между тегами . В результате получилось следующее:


Вызов file_put_contents не привел ни к чему, он просто написал «+ foo +» в файл. Вызов привел к выводу «42», который теперь находится в том месте, где этот код использовался.

Этот итоговый код HTML / JavaScript теперь отправляется клиенту, где он получает оценку , Вызов alert работает, а переменная foo нигде не используется.

Весь PHP-код выполняется на сервере до того, как клиент даже начнет выполнение какого-либо JavaScript. В ответе JavaScript, с которым может взаимодействовать JavaScript, нет кода PHP.

Чтобы вызвать некоторый код PHP, клиент должен будет отправить новый HTTP-запрос на сервер. Это может произойти с использованием одного из трех возможных способов:

  1. Ссылка, которая заставляет браузер загружать новую страницу.
  2. Подача формы, которая передает данные на сервер и загружает новую страницу.
  3. Запрос AJAX , который является техникой Javascript, чтобы сделать обычный HTTP-запрос на сервер (например, 1. и 2. будет), но без оставляя текущую страницу.

Вот более подробный изложение этого метода

Вы также можете использовать JavaScript, чтобы браузер открыл новую страницу с помощью window.location или отправить форму, подражая возможностям 1 и 2.

86
задан Joe Phillips 12 January 2009 в 18:14
поделиться

5 ответов

Я все время использую готовые заявления в Android, это довольно просто:

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("SELECT * FROM Country WHERE code = ?");
stmt.bindString(1, "US");
stmt.execute();
23
ответ дан jasonhudgins 24 August 2018 в 04:18
поделиться
  • 1
    Я не знаю, как этот ответ может иметь так много голосов. Выполнение SQLIteStatement # execute не должно использоваться для запросов Sql, только для операторов. Проверьте developer.android.com/reference/android/database/sqlite/… – simao 14 February 2011 в 01:55
  • 2
    Тогда как вы должны использовать подготовленный оператор для запроса данных? – Juan Mendes 23 March 2011 в 19:42
  • 3
    Обратите внимание, что SQLiteStatement.bindXXX() имеет индекс на основе 1, а не 0, как большинство из них. – Simulant 14 November 2013 в 11:02
  • 4
    @jasonhudgins Почему бы просто не заменить SELECT на INSERT? Я только что пришел из этой темы, где вы путаете новичка – keyser 3 May 2014 в 16:29
  • 5
    идеальный пример менталитета стада, который выдвигает и принимает ответ, совершенно неверный – feeling unwelcome 30 June 2015 в 17:00

Чтобы получить курсор, вы не можете использовать compiledStatement. Однако, если вы хотите использовать полностью подготовленный оператор SQL, я рекомендую адаптировать метод jbaez ... Используя db.rawQuery() вместо db.query().

1
ответ дан Deepzz 24 August 2018 в 04:18
поделиться

Если вы хотите, чтобы курсор возвращался, вы можете рассмотреть что-то вроде этого:

SQLiteDatabase db = dbHelper.getWritableDatabase();

public Cursor fetchByCountryCode(String strCountryCode)
{
    /**
     * SELECT * FROM Country
     *      WHERE code = US
     */
    return cursor = db.query(true, 
        "Country",                        /**< Table name. */
        null,                             /**< All the fields that you want the 
                                                cursor to contain; null means all.*/
        "code=?",                         /**< WHERE statement without the WHERE clause. */
        new String[] { strCountryCode },    /**< Selection arguments. */
        null, null, null, null);
}

/** Fill a cursor with the results. */
Cursor c = fetchByCountryCode("US");

/** Retrieve data from the fields. */
String strCountryCode = c.getString(cursor.getColumnIndex("code"));

/** Assuming that you have a field/column with the name "country_name" */
String strCountryName = c.getString(cursor.getColumnIndex("country_name"));

См. этот фрагмент Genscripts , если вы хотите получить более полную версию. Обратите внимание, что это параметризованный SQL-запрос, поэтому по существу это подготовленный оператор.

21
ответ дан Otto Allmendinger 24 August 2018 в 04:18
поделиться
  • 1
    Небольшая ошибка в коде выше: должна быть «новая строка» [] {strCountryCode}, & quot; вместо «новой строки» (strCountryCode) ». – Pierre-Luc Simard 15 April 2011 в 20:49
  • 2
    Вам нужно переместить курсор, прежде чем вы сможете получить данные – Chin 23 November 2014 в 22:00

Пример jasonhudgins не будет работать. Вы не можете выполнить запрос с stmt.execute() и получить значение (или Cursor) назад.

Вы можете только предварительно скомпилировать утверждения, которые либо не возвращают никакие строки вообще (например, вставка, или create table statement) или одну строку и столбец (и используйте simpleQueryForLong() или simpleQueryForString()).

9
ответ дан redfish64 24 August 2018 в 04:18
поделиться

Для подготовленных операторов SQLite в Android есть SQLiteStatement . Подготовленные заявления помогают ускорить работу (особенно для операторов, которые нужно выполнять несколько раз), а также помогают избежать атак на атаку. См. в этой статье для общего обсуждения подготовленных операторов.

SQLiteStatement предназначен для использования с операторами SQL, которые не возвращают несколько значений. (Это означает, что вы не будете использовать их для большинства запросов.) Ниже приведены некоторые примеры:

Создать таблицу

String sql = "CREATE TABLE table_name (column_1 INTEGER PRIMARY KEY, column_2 TEXT)";
SQLiteStatement stmt = db.compileStatement(sql);
stmt.execute();

execute() не возвращает значение, поэтому его следует использовать с CREATE и DROP, но не предназначено для использования с SELECT, INSERT, DELETE и UPDATE, потому что они возвращают значения. (Но см. этот вопрос .)

Вставить значения

String sql = "INSERT INTO table_name (column_1, column_2) VALUES (57, 'hello')";
SQLiteStatement statement = db.compileStatement(sql);
long rowId = statement.executeInsert();

Обратите внимание, что executeInsert() , а не execute(). Конечно, вы не хотели бы всегда вводить одни и те же вещи в каждой строке. Для этого вы можете использовать привязки .

String sql = "INSERT INTO table_name (column_1, column_2) VALUES (?, ?)";
SQLiteStatement statement = db.compileStatement(sql);

int intValue = 57;
String stringValue = "hello";

statement.bindLong(1, intValue); // 1-based: matches first '?' in sql string
statement.bindString(2, stringValue);  // matches second '?' in sql string

long rowId = statement.executeInsert();

Обычно вы используете подготовленные инструкции, когда хотите быстро повторять что-то (например, INSERT). Подготовленный оператор делает так, что SQL-запрос не должен анализироваться и скомпилироваться каждый раз. Вы можете ускорить еще больше, используя транзакции . Это позволяет сразу применить все изменения. Вот пример:

String stringValue = "hello";
try {

    db.beginTransaction();
    String sql = "INSERT INTO table_name (column_1, column_2) VALUES (?, ?)";
    SQLiteStatement statement = db.compileStatement(sql);

    for (int i = 0; i < 1000; i++) {
        statement.clearBindings();
        statement.bindLong(1, i);
        statement.bindString(2, stringValue + i);
        statement.executeInsert();
    }

    db.setTransactionSuccessful(); // This commits the transaction if there were no exceptions

} catch (Exception e) {
    Log.w("Exception:", e);
} finally {
    db.endTransaction();
}

Ознакомьтесь с этими ссылками для получения более подробной информации о транзакциях и ускорения вставки баз данных.

Обновить строки

Это базовый пример. Вы также можете применить понятия из раздела выше.

String sql = "UPDATE table_name SET column_2=? WHERE column_1=?";
SQLiteStatement statement = db.compileStatement(sql);

int id = 7;
String stringValue = "hi there";

statement.bindString(1, stringValue);
statement.bindLong(2, id);

int numberOfRowsAffected = statement.executeUpdateDelete();

Удалить строки

Метод executeUpdateDelete() также может использоваться для операторов DELETE и был введен в API 11. См. этот Q & amp; A .

Вот пример.

try {

    db.beginTransaction();
    String sql = "DELETE FROM " + table_name +
            " WHERE " + column_1 + " = ?";
    SQLiteStatement statement = db.compileStatement(sql);

    for (Long id : words) {
        statement.clearBindings();
        statement.bindLong(1, id);
        statement.executeUpdateDelete();
    }

    db.setTransactionSuccessful();

} catch (SQLException e) {
    Log.w("Exception:", e);
} finally {
    db.endTransaction();
}

Query

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

String sql = "SELECT COUNT(*) FROM table_name";
SQLiteStatement statement = db.compileStatement(sql);
long result = statement.simpleQueryForLong();

Обычно вы запускаете метод query() для SQLiteDatabase , чтобы получить курсор.

SQLiteDatabase db = dbHelper.getReadableDatabase();
String table = "table_name";
String[] columnsToReturn = { "column_1", "column_2" };
String selection = "column_1 =?";
String[] selectionArgs = { someValue }; // matched to "?" in selection
Cursor dbCursor = db.query(table, columnsToReturn, selection, selectionArgs, null, null, null);

Для получения более подробной информации о запросах см. этот ответ .

136
ответ дан Suragch 24 August 2018 в 04:18
поделиться
  • 1
    Просто напоминание: методы .bindString / .bindLong / ... основаны на 1. – Denys Vitali 26 April 2016 в 15:25
  • 2
    Я смотрел под капотом удобных методов Android, таких как .query, .insert и .delete, и заметил, что они используют SQLiteStatement под капотом. Не было бы проще просто использовать удобные методы вместо того, чтобы строить свои собственные заявления? – Nicolás Carrasco 5 July 2016 в 22:04
  • 3
    @ NicolásCarrasco, это было давно, так как я работал над этим, поэтому теперь я немного ржавый. Для запросов и одиночных вставок, обновлений и удалений я бы определенно использовал удобные методы. Однако, если вы делаете массовые вставки, обновления или удаления, я бы рассмотрел подготовленные заявления вместе с транзакцией. Что касается использования SQLiteStatement под капотом и насколько удобные методы достаточно хороши, я не могу с этим поговорить. Думаю, я бы сказал, если удобные методы выполняются достаточно быстро для вас, а затем используйте их. – Suragch 6 July 2016 в 20:49
Другие вопросы по тегам:

Похожие вопросы: