以插入数据为例,有三种方法:
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对象的相应方法。 原文链接:https://www.f2er.com/sqlite/199899.html