如何在Android中的SQlite中使用预准备语句?
对于Android中准备好的SQLite语句,有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();
请注意,使用该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();
通常,当您想要多次快速重复某些内容(如INSERT)时,您可以使用预准备语句.准备好的语句使得每次都不必解析和编译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(); }
查看这些链接,了解有关事务的更多信息以及加快数据库插入的速度.
SQLite中的原子提交(深入解释,请参阅第3部分)
数据库事务
Android SQLite批量插入和更新示例
带有INSERT Prepared语句的Android SQLite事务示例
在Android上增加您的SQLite插件
/sf/ask/17360801/
更新行
这是一个基本的例子.您还可以应用上一节中的概念.
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();
通常,您将运行SQLiteDatabase的query()
方法来获取游标.
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);
有关查询的更多详细信息,请参阅此答案
我一直在Android中使用预处理语句,这非常简单:
SQLiteDatabase db = dbHelper.getWritableDatabase(); SQLiteStatement stmt = db.compileStatement("SELECT * FROM Country WHERE code = ?"); stmt.bindString(1, "US"); stmt.execute();
如果你想要一个返回光标,那么你可能会考虑这样的事情:
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()
并获取值(或a Cursor
).
您只能预编译根本不返回任何行的语句(例如insert或create table语句)或单个行和列(并使用simpleQueryForLong()
或simpleQueryForString()
).