Andrioid SQLite 操作与SQLiteStatement关系
发布时间:2020-12-12 19:49:50 所属栏目:百科 来源:网络整理
导读:以插入数据为例,有三种方法: 1)直接拼接SQL语句,执行execSQL方法; 2)借用ContentValues进行插入; 3)使用compileStatement进行插入; 1)直接拼接SQL语句,执行execSQL方法 String sql = "create table msgTable(uid INTEGER NOT NULL,msg TEXT NOT N
以插入数据为例,有三种方法: 1)直接拼接SQL语句,执行execSQL方法; 2)借用ContentValues进行插入; 3)使用compileStatement进行插入; 1)直接拼接SQL语句,执行execSQL方法 String sql = "create table msgTable(uid INTEGER NOT NULL,msg TEXT NOT NULL)"; db.execSQL(sql); 缺点:存在SQL注入危险; 源码分析: execSQL 调用关系如下: public void execSQL(String sql) throws SQLException { executeSql(sql,null); } public void execSQL(String sql,Object[] bindArgs) throws SQLException { if (bindArgs == null) { throw new IllegalArgumentException("Empty bindArgs"); } executeSql(sql,bindArgs); } private int executeSql(String sql,Object[] bindArgs) throws SQLException { if (DatabaseUtils.getSqlStatementType(sql) == DatabaseUtils.STATEMENT_ATTACH) { disableWriteAheadLogging(); mHasAttachedDbs = true; } SQLiteStatement statement = new SQLiteStatement(this,sql,bindArgs); try { return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { statement.close(); } } 从调用关系看:execSQL调用的本质就是创建SQLiteStatement对象,调用其executeUpdateDelete插入方法, 而executeUpdateDelete() 方法调用native c++方法,具体如下: public int executeUpdateDelete() { try { saveSqlAsLastSqlStatement(); acquireAndLock(WRITE); int numChanges = 0; if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) { // since the statement doesn't have to be prepared,// call the following native method which will not prepare // the query plan native_executeSql(mSql); } else { numChanges = native_execute(); } return numChanges; } finally { releaseAndUnlock(); } } 2)借用ContentValues进行插入 ContentValues values = new ContentValues(); values.put("uid",12); values.put("msg","test"); long newRowId = db.insert("msgTable",null,values); 优点:解决了执行纯SQL语句引入的sql注入漏洞。 源码分析: public long insert(String table,String nullColumnHack,ContentValues values) { try { return insertWithOnConflict(table,nullColumnHack,values,CONFLICT_NONE); } catch (SQLException e) { Log.e(TAG,"Error inserting " + values,e); return -1; } } public long insertWithOnConflict(String table,ContentValues initialValues,int conflictAlgorithm) { StringBuilder sql = new StringBuilder(); sql.append("INSERT"); sql.append(CONFLICT_VALUES[conflictAlgorithm]); sql.append(" INTO "); sql.append(table); sql.append('('); Object[] bindArgs = null; int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0; if (size > 0) { bindArgs = new Object[size]; int i = 0; for (String colName : initialValues.keySet()) { sql.append((i > 0) ? "," : ""); sql.append(colName); bindArgs[i++] = initialValues.get(colName); } sql.append(')'); sql.append(" VALUES ("); for (i = 0; i < size; i++) { sql.append((i > 0) ? ",?" : "?"); } } else { sql.append(nullColumnHack + ") VALUES (NULL"); } sql.append(')'); SQLiteStatement statement = new SQLiteStatement(this,sql.toString(),bindArgs); try { return statement.executeInsert(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { statement.close(); } } 使用ContentValues 最终是创建SQLiteStatement对象,并调用executeInsert()方法。 3)使用compileStatement进行插入 SQLiteStatement sqLiteStatement = db.compileStatement("insert into msgTable(uid,msg) values(?,?)"); sqLiteStatement.bindLong(1,12); sqLiteStatement.bindString(3,"text"); long newRowId = sqLiteStatement.executeInsert(); 源码分析: public SQLiteStatement compileStatement(String sql) throws SQLException { verifyDbIsOpen(); return new SQLiteStatement(this,null); }compileStatement 更加直接,之间是根据传入的参数,创建一个SQLiteStatement对象。 小结: 对于执行纯sql,ContentValues和compileStatement最终都是new 一个SQLiteStatement对象,并调用SQLiteStatement对象的相应方法。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |