Wie verwende ich vorbereitete Anweisungen in SQlite in Android?
Wie verwende ich vorbereitete Anweisungen in SQlite in Android?
Antworten:
Ich verwende die ganze Zeit vorbereitete Anweisungen in Android, es ist ganz einfach:
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO Country (code) VALUES (?)");
stmt.bindString(1, "US");
stmt.executeInsert();
SQLiteStatement.bindXXX()
es einen 1-basierten Index gibt, der nicht wie die meisten auf 0 basiert.
Für vorbereitete SQLite-Anweisungen in Android gibt es SQLiteStatement . Mit vorbereiteten Anweisungen können Sie die Leistung beschleunigen (insbesondere bei Anweisungen, die mehrmals ausgeführt werden müssen) und Einspritzangriffe vermeiden. In diesem Artikel finden Sie eine allgemeine Diskussion zu vorbereiteten Aussagen.
SQLiteStatement
soll mit SQL-Anweisungen verwendet werden, die nicht mehrere Werte zurückgeben. (Das bedeutet, dass Sie sie für die meisten Abfragen nicht verwenden würden.) Nachfolgend einige Beispiele:
String sql = "CREATE TABLE table_name (column_1 INTEGER PRIMARY KEY, column_2 TEXT)";
SQLiteStatement stmt = db.compileStatement(sql);
stmt.execute();
Die execute()
Methode gibt keinen Wert zurück, daher ist die Verwendung mit CREATE und DROP angemessen, jedoch nicht die Verwendung mit SELECT, INSERT, DELETE und UPDATE, da diese Werte zurückgeben. (Aber siehe diese Frage .)
String sql = "INSERT INTO table_name (column_1, column_2) VALUES (57, 'hello')";
SQLiteStatement statement = db.compileStatement(sql);
long rowId = statement.executeInsert();
Beachten Sie, dass die executeInsert()
Methode anstelle von verwendet wird execute()
. Natürlich möchten Sie nicht immer in jeder Zeile die gleichen Dinge eingeben. Dafür können Sie Bindungen verwenden .
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();
Normalerweise verwenden Sie vorbereitete Anweisungen, wenn Sie etwas (wie ein INSERT) schnell viele Male wiederholen möchten. Die vorbereitete Anweisung sorgt dafür, dass die SQL-Anweisung nicht jedes Mal analysiert und kompiliert werden muss. Mit Transaktionen können Sie die Dinge noch schneller machen . Dadurch können alle Änderungen gleichzeitig übernommen werden. Hier ist ein Beispiel:
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();
}
Weitere Informationen zu Transaktionen und zur Beschleunigung von Datenbankeinfügungen finden Sie unter diesen Links.
Dies ist ein grundlegendes Beispiel. Sie können auch die Konzepte aus dem obigen Abschnitt anwenden.
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();
Die executeUpdateDelete()
Methode kann auch für DELETE-Anweisungen verwendet werden und wurde in API 11 eingeführt. Siehe diese Fragen und Antworten .
Hier ist ein Beispiel.
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();
}
Normalerweise möchten Sie beim Ausführen einer Abfrage einen Cursor mit vielen Zeilen zurückerhalten. Dafür ist es aber nicht SQLiteStatement
. Sie führen damit keine Abfrage aus, es sei denn, Sie benötigen nur ein einfaches Ergebnis, z. B. die Anzahl der Zeilen in der Datenbank, mit denen Sie arbeiten könnensimpleQueryForLong()
String sql = "SELECT COUNT(*) FROM table_name";
SQLiteStatement statement = db.compileStatement(sql);
long result = statement.simpleQueryForLong();
Normalerweise führen Sie die query()
Methode SQLiteDatabase aus , um einen Cursor zu erhalten.
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);
In dieser Antwort finden Sie weitere Informationen zu Abfragen.
clearBindings()
setzt sie jedoch nicht nur auf null
(siehe Quellcode ). Ich betrachte es als Löschen des Zustands, so dass nichts ihn von der vorherigen Schleife beeinflusst. Vielleicht ist das aber nicht nötig. Ich würde mich über jemanden freuen, der Kommentare abgeben kann.
Wenn Sie bei der Rückkehr einen Cursor wünschen, können Sie Folgendes in Betracht ziehen:
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"));
Sehen Sie sich dieses Snippet Genscripts an, falls Sie ein vollständigeres wünschen. Beachten Sie, dass dies eine parametrisierte SQL-Abfrage ist, also im Wesentlichen eine vorbereitete Anweisung.
Jasonhudgins Beispiel wird nicht funktionieren. Sie können eine Abfrage nicht mit ausführen stmt.execute()
und einen Wert (oder a Cursor
) zurückerhalten.
Sie können nur Anweisungen vorkompilieren, die entweder überhaupt keine Zeilen zurückgeben (z. B. eine Einfügung oder eine Tabellenanweisung erstellen) oder eine einzelne Zeile und Spalte (und simpleQueryForLong()
oder verwenden simpleQueryForString()
).