1

我有一些与 sqlitedatabase 有关的问题。我创建了两个线程。一个用于 web 服务调用并插入数据库,第二个线程用于检索所有数据库数据。但我遇到了一些错误:

 09-18 13:45:48.724: E/SQLiteDatabase(7189): android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode

我的代码如下:

Mainactivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        dbHelper = new DbHelper(this);

        setContentView(R.layout.activity_main);
        try {
            dbHelper.createDataBase();
        } catch (IOException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {

            @Override
            public void run() {

                try {
                    Log.i("data", "webAllBrokers thread start");

                    GetAllBrokers(getApplicationContext());
                    // GetAllBrokers(getApplicationContext());
                    Log.i("data", "webAllBrokers thread complete");
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                Log.i("data", "SelectAllData thread start.");
                SelectAllData();
                Log.i("data", "SelectAllData thread complete");
            }

        }).start();

    }

    private void SelectAllData() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 100; i++) {
            TblBroker.SelectAll(dbHelper);
        }

    }

    public static void GetAllBrokers(Context context) throws IOException,
            XmlPullParserException, JSONException {
        // webservice call for retrieve data
        String result = GetAllBrokers(context, "Admin001");
        ArrayList<ModelBroker> lstBrokers = JsonParserGetAllBrokers
                .parserString(result);

        TblBroker.deleteAll(dbHelper);

        TblBroker.insert(dbHelper, lstBrokers);

    }

另一个文件是 dbhelper 文件:

DbHelper.java

public class DbHelper extends SQLiteOpenHelper {


    // The Android's default system path of your application database.
    private static String PACKAGENAME = "com.example.webservicedemocallbackgroundwebservice";
    private static String DB_PATH = "/data/data/" + PACKAGENAME + "/databases/";
    private static String DB_NAME = "GRSL_Sales_DB.sqlite";
    public static int DELETED = 1;
    public static int UPDATED = 2;
    public static int NEW_RECORD = 3;
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();
    private SQLiteDatabase myDataBase;

    private final Context myContext;
    private String TAG = "DbHelper";

    /**
     * Constructor Takes and keeps a reference of the passed context in order to
     * access to the application assets and resources.
     * 
     * @param context
     */
    public DbHelper(final Context context) {
        super(context, DB_NAME, null, 1);
        this.myContext = context;

    }

    /**
     * Creates a empty database on the system and rewrites it with your own
     * database.
     * */
    public final void createDataBase() throws IOException {

        final boolean dbExist = checkDataBase();
        SQLiteDatabase db_Read = null;
        if (dbExist) {
            // do nothing - database already exist
        } else {
            // By calling this method and empty database will be created into
            // the default system path
            // of your application so we are gonna be able to overwrite that
            // database with our database.
            // By calling this method and empty database will be created into
            // the default system path
            // of your application so we are gonna be able to overwrite that
            // database with our database.
            // db_Read = this.getReadableDatabase(DB_Internal);
            db_Read = this.getReadableDatabase();
            db_Read.close();

            copyDataBase();

        }
    }

    /**
     * Restore whole database without any data
     * 
     * @throws IOException
     */
    public final void RestoreDatabase() throws IOException {
        SQLiteDatabase db_Read = this.getReadableDatabase();
        db_Read.close();

        copyDataBase();
        Log.i(TAG, "Database REstored");
    }

    /**
     * Check if the database already exist to avoid re-copying the file each
     * time you open the application.
     * 
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase() {
        final File dbFile = new File(DB_PATH + DB_NAME);
        return dbFile.exists();
    }

    /**
     * Copies your database from your local assets-folder to the just created
     * empty database in the system folder, from where it can be accessed and
     * handled. This is done by transfering bytestream.
     * 
     * @throws IOException
     * */
    private void copyDataBase() throws IOException {

        // Open your local db as the input stream
        final InputStream myInput = myContext.getAssets().open(DB_NAME);

        // Path to the just created empty db
        final String outFileName = DB_PATH + DB_NAME;

        // Open the empty db as the output stream
        final OutputStream myOutput = new FileOutputStream(outFileName);

        // transfer bytes from the inputfile to the outputfile
        final byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        // Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

    public final synchronized SQLiteDatabase openDataBase() {
        // Log.i("data", "data openDataBase");
        // Open the database
        final String myPath = DB_PATH + DB_NAME;
        Log.i("database", "data openDataBase" + myDataBase);

        if (myDataBase == null) {
            Log.i("database", "data openDataBase");
            myDataBase = SQLiteDatabase.openDatabase(myPath, null,
                    SQLiteDatabase.OPEN_READWRITE);
            myDataBase.beginTransaction();
        } 
        return myDataBase;
    }

    @Override
    public final synchronized void close() {
        // Log.i("data", "data closeDataBase");

        if (myDataBase != null) {
            Log.i("database", "data closeDataBase");
            myDataBase.setTransactionSuccessful();
            myDataBase.endTransaction();
            myDataBase.close();
            myDataBase = null;
        }
        super.close();
    }

    @Override
    public void onCreate(final SQLiteDatabase arg0) {
    }

    @Override
    public void onUpgrade(final SQLiteDatabase arg0, final int arg1,
            final int arg2) {
    }
}

我的表格文件是:

TblBroker.java

public class TblBroker {
    public static final String TABLENAME = "Broker";
    public static final String ID = "ID";
    public static final String SAPCODE = "SAPCode";
    public static final String DISCRIPTION = "Discription";
    public static final String ISACTIVE = "IsActive";
    public static final String ISDELETED = "IsDeleted";
    public static final String City = "City";

    /**
     * 
     * SelectAll
     * 
     * @param dbaConnection
     * @return ArrayList<ModelBroker>
     */
    public static ArrayList<ModelBroker> SelectAll(DbHelper dbaConnection) {
        Log.i("data", "SelectAll start");
        ArrayList<ModelBroker> broker_aList = new ArrayList<ModelBroker>();

        SQLiteDatabase sqldb = dbaConnection.openDataBase();
        Cursor cursor = sqldb.rawQuery("Select * From " + TblBroker.TABLENAME,
                null);
        if (cursor != null && !cursor.isClosed())// If CursorBroker is null then
                                                    // do
        // nothing
        {
            if (cursor.moveToFirst()) {
                do {
                    // Set broker information in model.
                    ModelBroker modelBroker = new ModelBroker();
                    modelBroker.setID(cursor.getInt(cursor
                            .getColumnIndex(TblBroker.ID)));
                    modelBroker.setSAPCode(cursor.getString(cursor
                            .getColumnIndex(TblBroker.SAPCODE)));
                    modelBroker.setDiscription(cursor.getString(cursor
                            .getColumnIndex(TblBroker.DISCRIPTION)));
                    modelBroker.setIsDeleted(cursor.getString(cursor
                            .getColumnIndex(TblBroker.ISDELETED)));
                    modelBroker.setIsActive(cursor.getString(cursor
                            .getColumnIndex(TblBroker.ISACTIVE)));
                    modelBroker.setCity(cursor.getString(cursor
                            .getColumnIndex(TblBroker.City)));
                    broker_aList.add(modelBroker);
                } while (cursor.moveToNext());
            }
            cursor.close();
        }
        Log.i("data", "SelectAll end");
        dbaConnection.close();
        return broker_aList;
    }

    public static long insert(DbHelper dbaConnection,
            ArrayList<ModelBroker> listbroker) {

        long id = 0;
        SQLiteDatabase sqldb = dbaConnection.openDataBase();

        for (int i = 0; i < listbroker.size(); i++) {

            ModelBroker broker = listbroker.get(i);
            ContentValues values = new ContentValues();
            values.put(TblBroker.SAPCODE, broker.getSAPCode());
            values.put(TblBroker.DISCRIPTION, broker.getDiscription());
            values.put(TblBroker.ISACTIVE, broker.getIsActive());
            values.put(TblBroker.ISDELETED, broker.getIsDeleted());
            values.put(TblBroker.City, broker.getCity());
            Log.i("data", "sqldb.isOpen()=" + sqldb.isOpen());
            id = sqldb.insert(TblBroker.TABLENAME, null, values);
        }

        Log.i("data", "1 st loop end");
        Log.i("data", "2nd  loop start");
        for (int i = 0; i < listbroker.size(); i++) {
            ModelBroker broker = listbroker.get(i);
            ContentValues values = new ContentValues();
            values.put(TblBroker.SAPCODE, broker.getSAPCode());
            values.put(TblBroker.DISCRIPTION, broker.getDiscription());
            values.put(TblBroker.ISACTIVE, broker.getIsActive());
            values.put(TblBroker.ISDELETED, broker.getIsDeleted());
            values.put(TblBroker.City, broker.getCity());
            id = sqldb.insert(TblBroker.TABLENAME, null, values);
        }

        Log.i("data", "2nd loop end");
        // Insert
        // query
        // of
        // SQLiteDatabase
        // class.
        dbaConnection.close();
        return id;

    }

    public static int deleteAll(DbHelper dbaConnection) {
        SQLiteDatabase sqldb = dbaConnection.openDataBase();
        int row = sqldb.delete(TABLENAME, null, null);// Delete

        sqldb.close();
        sqldb = null;
        return row;
    }

}

请给我一些解决方案。当一个线程正在运行并打开数据库时,那时另一个线程正在打开数据库。所以请找到并发问题的解决方案。

4

2 回答 2

7

默认情况下, Sqlite在 Android 上以序列化模式运行。这意味着多个线程可以同时访问数据库,并通过使用同步锁来维护线程安全。

您可以使用setLockingEnabled(boolean lockingEnabled)将其关闭。但是,这将使您的数据库不安全,您必须小心并自己处理同步。

我猜你的问题在于你的架构而不是线程。我建议您重新考虑应用程序的架构,这样您就不必使用数据库的线程安全功能。

于 2013-09-18T09:17:52.223 回答
0

我在不同的表中插入不同的行时遇到了类似的问题,尝试使用这个

   db.beginTransactionNonExclusive();
   try {
       //do some insertions or whatever you need
       db.setTransactionSuccessful();
   } finally {
       db.endTransaction();
   }

我尝试使用 db.beginTransaction 但它锁定了 bd

于 2015-06-10T17:13:28.223 回答