在android中记录SQL查询

在android中记录SQL查询,android,sqlite,logging,Android,Sqlite,Logging,我正在使用query函数为我的表构建SQL查询。有没有办法查看实际运行的查询?比如,把它记录在什么地方 到目前为止,我所能做的最好的事情就是使用断点查看游标的成员mQuery。不过我想自动输出查询。这个成员当然不是公共成员,也没有getter 为了记录在案,这里是公认答案的实现 /** * Implement the cursor factory in order to log the queries before returning * the cursor * * @autho

我正在使用
query
函数为我的表构建SQL查询。有没有办法查看实际运行的查询?比如,把它记录在什么地方


到目前为止,我所能做的最好的事情就是使用断点查看游标的成员mQuery。不过我想自动输出查询。这个成员当然不是公共成员,也没有getter


为了记录在案,这里是公认答案的实现

/**
 * 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);
    }
}

我个人使用
java.util.log
log.w(“MYAPPNAME”、“我的文本…”)函数记录文本。它显示在Eclipse的日志视图中,可以对其进行过滤,以便只输出“MYAPPNAME”的日志。

到目前为止,我所能做的最好的事情是使用断点查看游标的成员mQuery。这个成员当然不是公共的,也没有getter,因此无法输出它。还有更好的建议吗

您可以将自己的
SQLiteDatabase.CursorFactory
应用于数据库。(请参阅参数)。这将允许您创建自己的
Cursor
子类,从而将查询保存在易于访问的字段中


编辑:事实上,您甚至不必为
游标
创建子类。只需让您工厂的
newCursor()
方法返回一个标准的
SQLiteCursor
,但在执行此操作之前要记录查询。

如果您使用ContentProvider访问数据库,我就是这样让它记录查询的。这不是一个完美的解决方案,但对发展有效

@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;
  }

它将抛出DatabaseNotClosed异常,但您将能够看到查询

如果是一次性的场景,我建议注入一个错误(例如,输入LIEK之类的表达式,而不是like!),并观察Eclipse LogCat是否有任何错误!嗯

使用
SQLiteQueryBuilder
非常简单
buildQuery()
返回原始sql字符串,然后可以记录该字符串:

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(ExampleTable.TABLE_NAME);
String sql = qb.buildQuery(projection, selection, null, null, sortOrder, null);
Log.d("Example", sql);
设置此属性后,不要忘记重新启动应用程序


还可以启用执行时间日志记录。此处提供了更多详细信息:

如果使用SQLiteDatabase的标准方法作为插入、更新和删除自定义游标,则Factory将无法工作

我基于SQLiteDatabase类实现了我的不是很好但很有效的解决方案。它只是重复insert、update和delete方法的逻辑,但没有语句,实际上是记录SQL语句

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());
    }
}
adb shell setprop log.tag.SQLiteLog V adb shell setprop log.tag.sqlitev语句 adb壳体止动块
adb shell start-1:记录无法访问的SQL查询没有帮助。在
SQLiteCursorFactory.newCursor()
中是否有方法访问
selectionArgs
,将其包含在
log
的输出中?仅供记录<代码>SQLiteCursor(数据库、主查询、编辑表、查询)自API 11级以来已被弃用,请使用
SQLiteCursor(masterQuery、editTable、query)。如何使用上述SQLiteCursorFactory?如果使用的是SQLiteOpenHelper,只需将SQLiteCursorFactory传递给助手构造函数中的父级,如下所示:
public DbHelper(上下文上下文){super(上下文,数据库名称,新SQLiteCursorFactory(true),数据库版本);}
工作得很好,但这会在绑定任何参数之前显示查询。是否有一种方法可以在绑定所有提供的参数后查看查询?这似乎适用于“读取”查询,但不适用于插入和更新。是否有一种解决方案也适用于插入和更新?通常如何打开查询日志记录?日志记录在哪里?已弃用,因为API级别11重新启动应用程序可能不够。如果没有,也运行以下命令:
adb shell stop
adb shell start
,它将重新启动所有程序,您将开始看到大量SQL。我没有启用SQLite详细日志记录,即使根据,日志记录选项有效且没有任何更改。日志记录在哪里?logcat?日志显示在logcat中,确保未启用过滤器,日志与应用程序id不关联。此外,如果要再次禁用日志:
adb shell setprop log.tag.SQLiteStatements INFO
对于缺少的uid->
adb shell su 0 start
adb shell su 0 stop
可以通过将
V
替换为
D
来反转此设置,因为这些是详细记录和调试日志级别的快捷方式。谢谢!我缺少行
adb shell setprop log.tag.SQLiteLog V
,它不想工作。现在是了!
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());
    }
}
0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)
adb shell setprop log.tag.SQLiteLog V adb shell setprop log.tag.SQLiteStatements V adb shell stop adb shell start