将值绑定到查询的原因是为了防止SQL-injection attack.

基本上,您将查询(包括占位符)发送到您的数据库并说“我的下一个查询将是这种形式,而不是其他!”.当攻击者然后注入不同的查询字符串(例如,通过表单字段)时,数据库会说“嘿,那不是你要发送的查询!”并向你抛出一个错误.

Since commands (which can be injected into your actual query as show in the linked article) are strings, the string-datatype is the more “dangerous” one.

If a user tries to inject some code into your field which should only take numbers and you try to cast/parse the input to an integer (before putting the value into your query), you’ll get an exception right away. With a string, there is no such kind security. Therefor, they have to be escaped probably.

That might be the reason that the bind values are all interpreted as strings.

以上是假的!如果您绑定的参数是字符串或整数并不重要,它们都同样危险.此外,在代码中预先检查您的值会产生大量的样板代码,容易出错并且不灵活!

为了防止您的应用程序进行SQL注入并加速多个数据库写入操作(使用具有不同值的相同查询),您应该使用“预准备语句”.在Android SDK中写入数据库的正确类是SQLiteStatement.

要创建预准备语句,请使用SQLiteDatabase对象的compileStatement()-method并使用正确的bindXX()方法(从SQLiteProgram继承)绑定相应的值(将用查询中的?标记替换):

SQLiteDatabase db = dbHelper.getWritableDatabase();

SQLiteStatement stmt = db.compileStatement("INSERT INTO SomeTable (name, age) values (?,?)");

// Careful! The index begins at 1, not 0 !!

stmt.bindString(1, "Jon");

stmt.bindLong(2, 48L);

stmt.execute();

// Also important! Clean up after yourself.

stmt.close();

遗憾的是,SQLiteStatement没有返回Cursor的重载,所以你不能将它用于SELECT语句.对于那些,您可以使用rawQuery(String,String []) – SQLiteDatabase的方法:

int number = getNumberFromUser();

String[] arguments = new String[]{String.valueOf(number)};

db.rawQuery("SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= ?", arguments);

请注意,rawQuery() – 方法为参数值采用String数组.这实际上没关系,SQLite会自动转换为正确的类型.只要字符串表示与SQL查询中的预期相同,就可以了.

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐