在android sqlite中执行并发操作(插入,检索数据)

yc0p9oo0  于 2023-06-23  发布在  SQLite
关注(0)|答案(1)|浏览(160)

我想问一个与执行并发操作有关的问题,例如在数据插入操作进行的同时插入大量数据和检索数据。我已经尝试了这种情况下的线程,但没有成功。
下面是从SQLite表中插入和检索数据的两个函数

public void insertData(List<ModelClass> list) {
        SQLiteDatabase dbase = this.getWritableDatabase();
        dbase.beginTransaction();
        try {
            ContentValues values = new ContentValues();
            for (ModelClass bokmark : list) {
                values.put(KEY_FILE_NAME, bokmark.getFileName());
                values.put(KEY_FILE_URI, String.valueOf(bokmark.getFileUri()));
                values.put(KEY_FILE_PATH, String.valueOf(bokmark.getFilePath()));
                values.put(KEY_MONTH_NAME, bokmark.getMonthName());
                values.put(KEY_DATE, bokmark.getAudioDate());

                dbase.insert(TABLE_DETAIL, null, values);
            }
            dbase.setTransactionSuccessful();
        } finally {
            dbase.endTransaction();
        }

        dbase.close();

    }

及以下功能检索数据

public ArrayList<ModelClass> getAllData() {
        ArrayList<ModelClass> bookmarkList = new ArrayList<ModelClass>();
        String selectQuery = "SELECT * FROM " + TABLE_DETAIL;
        //Log.e("selectQuery===>", "" + selectQuery);
        SQLiteDatabase dbase = this.getReadableDatabase();
        Cursor cursor = dbase.rawQuery(selectQuery, null);

        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {
                ModelClass bokmarks = new ModelClass();
                bokmarks.setFileName(cursor.getString(1));
                bokmarks.setFileUri(Uri.parse(cursor.getString(2)));
                bokmarks.setFilePath(cursor.getString(3));
                bokmarks.setMonthName(cursor.getString(4));
                bokmarks.setAudioDate(cursor.getString(5));

                bookmarkList.add(bokmarks);
            } while (cursor.moveToNext());
        }
        cursor.close();
        dbase.close();

        return bookmarkList;
    }

在搜索互联网上,一些链接建议使用线程。我试过用线,但没有运气。任何人都有这方面的指导,都是有帮助的。

6gpjuf90

6gpjuf901#

我建议不要关闭数据库,除非特别需要(比如说,如果数据库处于WAL模式,则将其备份为单个文件)。
每当你打开数据库时,它都是一个相对消耗资源的过程。如果您关闭数据库,那么随后将不得不以一定的代价打开它。
因此,您可能希望考虑使用单例(即具有打开的数据库的单个示例)。
但是,始终在使用完光标后关闭它(您正在执行此操作)。Cursor可以被视为一个文件,它使用操作系统有限的可用文件分配(大约1000个左右)中的一个。
关于从Cursor检索数据,则不是moveToFirst,而是dountil moveToNext返回0。您可以使用while(cursor.moveToNext) { .... }简化代码。使用硬编码的列偏移也是不可取的,例如bokmarks.setFileName(cursor.getString(1));,其中1是硬编码的列偏移量,依赖于第2列作为文件名列,如果游标中列的顺序发生变化,则必须进行更改。相反,您可以利用CursorgetColumnIndex方法根据列名获取偏移量,而不管它在Cursor中的位置。
把上面的放在一起(做一些假设),然后你可以有你的类扩展SQLiteOpenHelper(例如):

class MySQLiteOpenHelper extends SQLiteOpenHelper {

   public static final String DATABASE_FILENAME = "mydatabase.db";
   public static final int DATABASE_VERSION = 1;
   public static final String KEY_FILE_NAME = "kfn";
   public static final String KEY_FILE_URI = "kuri";
   public static final String KEY_FILE_PATH = "kpath";
   public static final String KEY_MONTH_NAME = "kmonth";
   public static final String KEY_DATE = "kdate";
   public static final String TABLE_DETAIL = "detail";

   @Override
   public void onCreate(SQLiteDatabase sqLiteDatabase) {

   }

   @Override
   public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

   }

   private MySQLiteOpenHelper(Context context) {
      super(context,DATABASE_FILENAME,null,DATABASE_VERSION);
   }

   private static volatile MySQLiteOpenHelper instance;
   public static MySQLiteOpenHelper getMySQLiteOpenHelperInstance(Context context) {
      if (instance==null) {
         instance = new MySQLiteOpenHelper(context);
      }
      return instance;
   }

   public void insertData(List<ModelClass> list) {
      SQLiteDatabase dbase = this.getReadableDatabase();
      dbase.beginTransaction();
      try {
         ContentValues values = new ContentValues();
         for (ModelClass bokmark : list) {
            values.put(KEY_FILE_NAME, bokmark.getFileName());
            values.put(KEY_FILE_URI, String.valueOf(bokmark.getFileUri()));
            values.put(KEY_FILE_PATH, String.valueOf(bokmark.getFilePath()));
            values.put(KEY_MONTH_NAME, bokmark.getMonthName());
            values.put(KEY_DATE, bokmark.getAudioDate());

            dbase.insert(TABLE_DETAIL, null, values);
         }
         dbase.setTransactionSuccessful();
      } finally {
         dbase.endTransaction();
      }
      //dbase.close(); /* <<<<<<<<<< inefficient database will be closed when App is stopped as part of App cleanup */
   }

   public ArrayList<ModelClass> getAllData() {
      ArrayList<ModelClass> bookmarkList = new ArrayList<ModelClass>();
      String selectQuery = "SELECT * FROM " + TABLE_DETAIL;
      //Log.e("selectQuery===>", "" + selectQuery);
      SQLiteDatabase dbase = this.getReadableDatabase();
      Cursor cursor = dbase.rawQuery(selectQuery, null);

      // looping through all rows and adding to list
      /* <<<<<<<<<< get the column offsfets according to the column name rather than hard coding the offsets >>>>>>>>>> */
      int fnidx = cursor.getColumnIndex(KEY_FILE_NAME);
      int uriidx = cursor.getColumnIndex(KEY_FILE_URI);
      int fpidx = cursor.getColumnIndex(KEY_FILE_PATH);
      int mnidx = cursor.getColumnIndex(KEY_MONTH_NAME);
      int didx = cursor.getColumnIndex(KEY_DATE);
      while (cursor.moveToNext()) { /*<<<<<<<<<< Simpler while loop */
         ModelClass bokmarks = new ModelClass();
         bokmarks.setFileName(cursor.getString(fnidx));
         bokmarks.setFileUri(parse(cursor.getString(uriidx)));
         bokmarks.setFilePath(cursor.getString(fpidx));
         bokmarks.setMonthName(cursor.getString(mnidx));
         bokmarks.setAudioDate(cursor.getString(didx));
         bookmarkList.add(bokmarks);
      }
      cursor.close();
      //dbase.close(); /* <<<<<<<<<< inefficient database will be closed when App is stopped as part of App cleanup */
      return bookmarkList;
   }
}

****注意**以上代码为原则代码,尚未编译运行,可能存在错误 *

至于在单独的线程中运行,有很多方法。经常遇到的问题是理解和编码检测和处理其他线程的完成,由主线程,无论何时发生。
我建议先看看https://developer.android.com/topic/performance/threads

相关问题