eine vorbereitete Anweisung ermöglicht es Ihnen, zwei Dinge
- beschleunigen die Leistung zu tun, da die Datenbank nicht die Aussage jedes Mal
- binden & Flucht Argumente in der Anweisung zu analysieren, benötigt also sind Sie speichern gegen Injection-Angriffe
ich weiß nicht genau, wo/wann Androids SQLite Implementierung sqlite3_prepare
tatsächlich verwendet (afiak nicht sqlite3_prepare_v2
- siehe here), aber ich t verwendet es sonst, Sie könnten Reached MAX size for compiled-sql statement cache errors nicht erhalten.
Also, wenn Sie die Datenbank abfragen wollen, müssen Sie auf die Implementierung verlassen, es gibt keine Möglichkeit, es mit SQLiteStatement
zu tun.
In Bezug auf die Injektionssicherheit hat jede Datenbankabfrage-, insert-, usw.-Methode (manchmal alternative) Versionen, mit denen Sie Argumente binden können.
z.wenn Sie wollen ein Cursor
aus
SELECT * FROM table WHERE column1='value1' OR column2='value2'
Cursor SQLiteDatabase#rawQuery(
String sql
erhalten: Voll SELECT
statment die einschließen können ?
überall
String[] selectionArgs
: Liste von Werten, die ?
ersetzen, in Reihenfolge sie erscheinen
)
Cursor c1 = db.rawQuery(
"SELECT * FROM table WHERE column1=? OR column2=?",
new String[] {"value1", "value2"}
);
Cursor SQLiteDatabase#query (
String table
,: Tabellenname, können umfassen JOIN
etc
String[] columns
,: Liste der Spalten erforderlich, null
= *
String selection
,: WHERE
Klausel withouth WHERE
kann/sollte ?
String[] selectionArgs
, umfassen: Liste von Werten, die ?
, ersetzen, um sie erscheinen
String groupBy
,: GROUP BY
Klausel w/o GROUP BY
String having
,: HAVING
Klausel w/o HAVING
String orderBy
: ORDER BY
Klausel w/o ORDER BY
)
Cursor c2 = db.query("table", null,
"column1=? OR column2=?",
new String[] {"value1", "value2"},
null, null, null);
Via ContentProviders - dieser Fall ist etwas anders, da Sie mit einem abstrakten Anbieter interagieren, keine Datenbank. Es gibt keine Garantie, dass es eine SQLite-Datenbank gibt, die die ContentProvider
unterstützt. Wenn Sie also nicht wissen, welche Spalten es gibt/wie der Provider intern arbeitet, sollten Sie sich an die Dokumentation halten.
Cursor ContentResolver#query(
Uri uri
,: eine URI, die die Datenquelle (intern in einer Tabelle übersetzt)
String[] projection
, Liste der Spalten erforderlich, null
= *
String selection
,: WHERE
Klausel ohne WHERE
kann/sollte enthalten ?
String[] selectionArgs
,: Liste von Werten, die ?
ersetzen, um sie
String sortOrder
erscheinen: ORDER BY
Klausel w/o ORDER BY
)
Cursor c3 = getContentResolver().query(
Uri.parse("content://provider/table"), null,
"column=? OR column2=?",
new String[] {"value1", "value2"},
null);
Hinweis: Wenn Sie auf LIMIT
hier möchten, können Sie hinzufügen es zu der ORDER BY
Klausel:
String sortOrder = "somecolumn LIMIT 5";
oder abhängig von der Implementierung der ContentProvider
es als Parameter an die Uri
hinzufügen:
Uri.parse("content://provider/table?limit=5");
// or better via buildUpon()
Uri audio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
audio.buildUpon().appendQueryParameter("limit", "5");
In allen Fällen ?
wird durch die maskierte Version von ersetzt werden, was Sie in dem bind Argumente setzen.
?
+ "hack'me"
= 'hack''me'
Outstanding Post, danke, half mir sehr viel. Zeiten wie diese lassen mich denken, dass wir in der Lage sein müssen, mehr als einmal zu modeln. – Louis
Auch wenn diese Antwort ruhig alt ist, gibt es einen Workaround, um irgendetwas anderes als einen String zu binden. Meine Abfragen fordern einen numerischen Wert als Bindung an, aber alle Methoden von SqliteDatabase verwenden ein String-Array. Und wenn ich das PreparedStatement selbst erstelle, kann ich die Abfrage ausführen, um den Cursor wiederherzustellen ... Ich kann nicht glauben, dass es keine Lösung gibt, aber ich habe es nicht gefunden. – AxelH
@AxelH Die Lösung ist, dass alles als String ausgedrückt werden kann. Verwenden Sie zum Beispiel 'String.valueOf (yourNumericThingHere)'. – zapl