在 Android 中使用准备好的语句进行查询?
Posted
技术标签:
【中文标题】在 Android 中使用准备好的语句进行查询?【英文标题】:Queries with prepared statements in Android? 【发布时间】:2012-04-09 01:38:00 【问题描述】:在 android 中,android.database.sqlite.SQLiteStatement
允许我在 SQLite 中使用准备好的语句来避免注入攻击。它的execute
方法适用于创建/更新/删除操作,但是对于返回游标之类的查询似乎没有任何方法。
现在在 ios 中,我可以创建 sqlite3_stmt*
类型的准备好的语句并将它们用于查询,所以我知道这不是 SQLite 的限制。如何在 Android 中使用准备好的语句执行查询?
【问题讨论】:
【参考方案1】:准备好的语句允许你做两件事
提高性能,因为数据库不需要每次都解析语句 在语句中绑定和转义参数,这样可以避免注入攻击我不确切知道 Android 的 SQLite 实现在何处/何时实际使用 sqlite3_prepare
(afiak 不是 sqlite3_prepare_v2
- 请参阅 here),但它确实使用了它,否则您无法获得 Reached MAX size for compiled-sql statement cache errors。
因此,如果您想查询数据库,您必须依赖实现,我不知道使用SQLiteStatement
来做到这一点。
关于注入安全性,每个数据库查询、插入等方法都有(有时是替代的)版本,允许您绑定参数。
例如如果你想得到一个Cursor
SELECT * FROM table WHERE column1='value1' OR column2='value2'
Cursor SQLiteDatabase#rawQuery(
String sql
, : 完整的 SELECT
声明,可以在任何地方包含 ?
String[] selectionArgs
:替换 ?
的值列表,按它们出现的顺序排列
)
Cursor c1 = db.rawQuery(
"SELECT * FROM table WHERE column1=? OR column2=?",
new String[] "value1", "value2"
);
Cursor SQLiteDatabase#query (
String table
, : 表名,可以包含JOIN
等
String[] columns
, :所需列的列表,null
= *
String selection
, : WHERE
没有WHERE
的子句可以/应该包括?
String[] selectionArgs
, : 替换 ?
的值列表,按它们出现的顺序排列
String groupBy
, : GROUP BY
子句不带 GROUP BY
String having
, : HAVING
子句不带 HAVING
String orderBy
: ORDER BY
子句 w/o ORDER BY
)
Cursor c2 = db.query("table", null,
"column1=? OR column2=?",
new String[] "value1", "value2",
null, null, null);
通过 ContentProviders - 这种情况略有不同,因为您与抽象提供者而不是数据库进行交互。确实不能保证有支持ContentProvider
的sqlite 数据库。因此,除非您知道有哪些列/提供程序在内部如何工作,否则您应该遵守文档中的说明。
Cursor ContentResolver#query(
Uri uri
, : 表示数据源的 URI(内部翻译成表格)
String[] projection
, :所需列的列表,null
= *
String selection
, : WHERE
子句没有 WHERE
可以/应该包括 ?
String[] selectionArgs
, :替换 ?
的值列表,按它们出现的顺序排列
String sortOrder
: ORDER BY
子句 w/o ORDER BY
)
Cursor c3 = getContentResolver().query(
Uri.parse("content://provider/table"), null,
"column=? OR column2=?",
new String[] "value1", "value2",
null);
提示:如果您想在此处添加LIMIT
,可以将其添加到ORDER BY
子句中:
String sortOrder = "somecolumn LIMIT 5";
或者根据ContentProvider
的实现将它作为参数添加到Uri
:
Uri.parse("content://provider/table?limit=5");
// or better via buildUpon()
Uri audio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
audio.buildUpon().appendQueryParameter("limit", "5");
在所有情况下,?
都将替换为您在绑定参数中输入的转义版本。
?
+ "hack'me"
= 'hack''me'
【讨论】:
出色的帖子,谢谢,对我帮助很大。像这样的时代让我觉得我们需要能够多次修改。 即使这个答案很老,是否有一种解决方法可以绑定除字符串之外的任何内容。我的查询请求绑定一个数值,但 SqliteDatabase 中的每个方法都使用一个字符串数组。如果我自己创建 PreparedStatement,我可以执行查询来恢复光标...我不敢相信没有解决方案,但我还没有找到它。 @AxelH 解决办法是一切都可以用字符串表示。例如使用String.valueOf(yourNumericThingHere)
。
当然可以,但是我的查询要求进行数值比较示例“columnX
使用带有 whereClause 'columnX
以上是关于在 Android 中使用准备好的语句进行查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何在另一个准备好的语句中使用 PreparedStatement 作为子查询