在android中loggingSQL查询
我正在使用query
function,以build立我的表的SQL查询。 有没有办法看到运行的实际查询? 例如logging在什么地方?
到目前为止,我所能做的最好的是使用断点来查看游标的成员mQuery。 我很想自动输出查询。 这个成员当然是不公开的,没有吸气。
只是为了logging,这是一个接受答案的实现。
/** * Implement the cursor factory in order to log the queries before returning * the cursor * * @author Vincent @ MarvinLabs */ public class SQLiteCursorFactory implements CursorFactory { private boolean debugQueries = false; public SQLiteCursorFactory() { this.debugQueries = false; } public SQLiteCursorFactory(boolean debugQueries) { this.debugQueries = debugQueries; } @Override public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) { if (debugQueries) { Log.d("SQL", query.toString()); } return new SQLiteCursor(db, masterQuery, editTable, query); } }
您可以将自己的SQLiteDatabase.CursorFactory
应用于数据库。 (请参阅openDatabase参数。)这将允许您创build您自己的Cursor
的子类,以便将查询保留在易于访问的字段中。
编辑 :其实,你甚至可能不需要子类化Cursor
。 只要你的工厂的newCursor()
方法返回一个标准的SQLiteCursor
,但在这之前logging查询。
adb shell setprop log.tag.SQLiteStatements VERBOSE
设置此属性后不要忘记重新启动您的应用程序。
也可以启用执行时间的logging。 更多细节可以在这里find: http : //androidxref.com/4.2.2_r1/xref/frameworks/base/core/java/android/database/sqlite/SQLiteDebug.java
adb shell setprop log.tag.SQLiteLog V adb shell setprop log.tag.SQLiteStatements V 亚行壳停止 adb shell启动
使用一个SQLiteQueryBuilder
很简单的。 buildQuery()
返回一个原始的sqlstring,然后可以logging:
SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(ExampleTable.TABLE_NAME); String sql = qb.buildQuery(projection, selection, null, null, sortOrder, null); Log.d("Example", sql);
到目前为止,我所能做的最好的是使用断点来查看游标的成员mQuery。 这个成员当然是不公开的,没有吸气剂,所以没办法输出。 有什么更好的build议?
如果它是一次性的情况下,我会build议注入一个错误(例如inputexpression式,像LIEK而不是LIKE!),并观看Eclipse LogCat的任何错误! HTH!
如果你使用SQLiteDatabase作为插入的标准方法,更新和删除自定义的CursorFactory将不起作用。
我实现了我不是很好,但基于SQLiteDatabase类的工作解决scheme。 它只是重复插入,更新和删除方法的逻辑,但没有语句,实际上做SQL语句的日志logging。
public class SQLiteStatementsLogger { private static final String TAG = SQLiteStatementsLogger.class.getSimpleName(); private static final String[] CONFLICT_VALUES = new String[] {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "}; public void logInsert(String table, String nullColumnHack, ContentValues values) { logInsertWithOnConflict(table, nullColumnHack, values, 0); } public static void logInsertWithOnConflict(String table, String nullColumnHack, 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(')'); sql.append(". ("); for (Object arg : bindArgs) { sql.append(String.valueOf(arg)).append(","); } sql.deleteCharAt(sql.length()-1).append(')'); Log.d(TAG, sql.toString()); } public static void logUpdate(String table, ContentValues values, String whereClause, String[] whereArgs) { logUpdateWithOnConflict(table, values, whereClause, whereArgs, 0); } public static void logUpdateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(CONFLICT_VALUES[conflictAlgorithm]); sql.append(table); sql.append(" SET "); // move all bind args to one array int setValuesSize = values.size(); int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length); Object[] bindArgs = new Object[bindArgsSize]; int i = 0; for (String colName : values.keySet()) { sql.append((i > 0) ? "," : ""); sql.append(colName); bindArgs[i++] = values.get(colName); sql.append("=?"); } if (whereArgs != null) { for (i = setValuesSize; i < bindArgsSize; i++) { bindArgs[i] = whereArgs[i - setValuesSize]; } } if (!TextUtils.isEmpty(whereClause)) { sql.append(" WHERE "); sql.append(whereClause); } sql.append(". ("); for (Object arg : bindArgs) { sql.append(String.valueOf(arg)).append(","); } sql.deleteCharAt(sql.length()-1).append(')'); Log.d(TAG, sql.toString()); } public static void logDelete(String table, String whereClause, String[] whereArgs) { StringBuilder sql = new StringBuilder("DELETE FROM " + table); if (!TextUtils.isEmpty(whereClause)) { sql.append(" WHERE " + whereClause); sql.append(". ("); for (Object arg : whereArgs) { sql.append(String.valueOf(arg)).append(","); } sql.deleteCharAt(sql.length()-1).append(')'); } Log.d(TAG, sql.toString()); } }
请注意不要在发行版本中使用logging器。 这可能会增加查询执行的时间。 你可以用这个代码行来检查构build是否处于debugging模式:
0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)
如果你正在使用ContentProvider来访问数据库,这就是我如何logging查询。 不是一个完美的解决scheme,但它的发展
@Override public boolean onCreate() { dbHelper = new MySQLiteHelper(getContext()); database=dbHelper.getWritableDatabase(); if(!database.isReadOnly()) database.execSQL("PRAGMA foreign_keys=ON;"); return true; } SQLiteDatabase.CursorFactory cursorFactory = new SQLiteDatabase.CursorFactory() { @Override public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) { Log.d(TAG, "Query: "+query); return new SQLiteCursor(db, masterQuery, editTable, query); } }; @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { String table =getTableName(uri); if(Constants.LOG_QUERIES){ database = SQLiteDatabase.openOrCreateDatabase(database.getPath(), cursorFactory); } Cursor cursor =database.query(table, projection, selection, selectionArgs, null, null, sortOrder); cursor.moveToFirst(); return cursor; }
它会抛出一个DatabaseNotClosedexception,但您将能够看到该查询
我个人使用java.util.Log
和Log.w("MYAPPNAME", "My text...")
函数loggingLog.w("MYAPPNAME", "My text...")
。 它显示在Eclipse的日志视图中,可以将其过滤为仅输出“MYAPPNAME”的日志。