Как использовать подготовленные заявления в SQlite в Android? - PullRequest
94 голосов
/ 11 января 2009

Как использовать подготовленные операторы в SQlite в Android?

Ответы [ 5 ]

152 голосов
/ 22 апреля 2015

Для подготовленных операторов 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();

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

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();

Обычно вы используете подготовленные операторы, когда хотите быстро что-то повторить (например, ВСТАВИТЬ) много раз. Подготовленный оператор делает так, что оператор 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. См. Эти вопросы и ответы .

Вот пример.

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();
}

Запрос

Обычно, когда вы запускаете запрос, вы хотите вернуть курсор назад с большим количеством строк. Это не то, для чего 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);

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

21 голосов
/ 03 сентября 2010

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

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 голосов
/ 12 января 2009

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

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("SELECT * FROM Country WHERE code = ?");
stmt.bindString(1, "US");
stmt.execute();
9 голосов
/ 06 июня 2010

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

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

1 голос
/ 14 октября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...