简体   繁体   English

Sqlite数据库使用线程锁定问题:Android

[英]Sqlite Database locked issue using threading : Android

I have some issue relating sqlitedatabase.i have create two thread.one is for webservice call and insert into database and second thread is for retrieving all database data.but i got some error: 我有一些有关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

my code is below: 我的代码如下:

Mainactivity.java 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);

    }

the other file is dbhelper file: 另一个文件是dbhelper文件:

DbHelper.java 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) {
    }
}

My table file is: 我的表文件是:

TblBroker.java 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;
    }

}

please give me some solution.when one thread is running and open db then at that time other thread is open db.so please find solution of concurrency problem. 请给我一些解决方案。当一个线程正在运行并打开db时,当时另一个线程正在打开db.so,请找到并发问题的解决方案。

Sqlite runs in Serialized mode on Android by default. Sqlite默认情况下在Android上以序列化模式运行。 This means that multiple threads can access the database simultaneously and thread-safety is maintained by using synchronized locks. 这意味着多个线程可以同时访问数据库,并且通过使用同步锁来维护线程安全性。

You can turn this off by using setLockingEnabled(boolean lockingEnabled) . 您可以使用setLockingEnabled(boolean lockEnabled)关闭此功能。 This will, however, make your db unsafe and you'll have to be careful and handle the synchronization yourself. 但是,这将使您的数据库不安全,因此必须小心并自己处理同步。

I would guess your problem lies in your architecture more than the threading. 我猜您的问题更多的是在于您的体系结构,而不是线程。 I suggest you re-think the architecture of your app so that you don't have to hack around with the thread-safety features of your db. 我建议您重新考虑应用程序的体系结构,以免您不必担心数据库的线程安全功能。

I had a similar problem problem inserting various row in different tables, try using this 我在类似的问题中将不同的行插入不同的表中,请尝试使用此

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

I tried with db.beginTransaction but it locked the bd 我尝试了db.beginTransaction,但它锁定了bd

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM