微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Andrioid SQLite 操作与SQLiteStatement关系


以插入数据为例,有三种方法
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.jb51.cc/sqlite/199899.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐