Як я можу використовувати підготовлені заяви в SQlite в Android?
Як я можу використовувати підготовлені заяви в SQlite в Android?
Відповіді:
Я постійно використовую підготовлені заяви в Android, це досить просто:
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO Country (code) VALUES (?)");
stmt.bindString(1, "US");
stmt.executeInsert();
SQLiteStatement.bindXXX()
має індекс на основі 1, а не 0, як більшість.
Для підготовлених операторів 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()
Метод не повертає значення , тому доцільно використовувати з створювати і видаляти , але не призначені для використання з 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();
Зазвичай ви використовуєте підготовлені висловлювання, коли хочете швидко повторити щось (наприклад, ВСТУП) багато разів. Підготовлений оператор робить так, що оператор 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()
Метод також може бути використаний для ВЕЬЕТЕ і був введений в API 11. Див цей Q & 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();
}
Зазвичай при запуску запиту потрібно повернути курсор з великою кількістю рядків. Але це не для чого 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);
Дивіться цю відповідь для отримання більш детальної інформації про запити.
clearBindings()
не просто встановлює їх null
(див. Вихідний код ). Я розглядаю це як очищення стану, щоб нічого не впливати на це з попереднього циклу. Можливо, це не потрібно. Буду радий тому, хто вміє коментувати.
Якщо ви хочете, щоб курсор повернувся, ви можете розглянути щось подібне:
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-запит, тому по суті це підготовлений оператор.
Приклад Jasonhudgins не буде працювати. Ви не можете виконати запит stmt.execute()
і повернути значення (або а Cursor
) назад.
Ви можете лише заздалегідь компілювати висловлювання, які або не повертають жодних рядків (наприклад, вставки або створення оператора таблиці), або одного рядка та стовпця (та використання simpleQueryForLong()
або simpleQueryForString()
).