android summary and finishing----Sqlite

  • Date:2015-4-23
  • Tag:android; sqlite; transaction; multithreading
  • Author:Snow
  • Email:[email protected]

First, the basic operation of Sqlite - addition, deletion, modification and query

1. Create or open a database

SQLiteDatabase db = openOrCreateDatabase(DATABASE_NAME, MODE_PRIVATE, null);

2. Create or delete table

db.execSQL("DROP TABLE IF EXISTS " + Student.TABLE_NAME);
        db.execSQL("CREATE TABLE " + Student.TABLE_NAME 
        + "(" 
        + Student.ID + " INTEGER PRIMARY KEY    AUTOINCREMENT, "
        + Student.NAME + " VARCHAR, "
        + Student.SCORE + " VARCHAR "
        + ");");

3. Insert data

if(db.delete(Student.TABLE_NAME, Student.NAME + "=?", new String[]{"wgc"}) == 0) {
            Log.v("base_operation", "删除失败!");
        } else {
            Log.v("base_operation", "删除成功!");
        }

4. Modify data

values.put(Student.NAME, "wgc2");
        values.put(Student.SCORE, "99");
        int rows = db.update(Student.TABLE_NAME, values, Student.NAME + "=?", new String[]{"wgc"});

5. Query data

Cursor cursor = db.rawQuery(
                "select * from " 
                + Student.TABLE_NAME
                + " where " + Student.NAME + "=?" 
                , new String[] {"wgc2"});
        Student student = new Student();
        while(cursor.moveToNext()){
            student.id = cursor.getString(cursor.getColumnIndex(Student.ID));
            student.name = cursor.getString(cursor.getColumnIndex(Student.NAME));
            student.score = cursor.getString(cursor.getColumnIndex(Student.SCORE));
            Log.v("base_operation", student.toString());
        }

Second, the transaction properties of Sqlite

When the application is initialized, if a large amount of data is inserted using the for+Insert method alone, the application response will be slow. Because the SQLite database is essentially a file on disk, some database operations are actually file operations. Frequent file operations are a time-consuming process, which greatly affects the storage speed of the database.

When sqlite inserts data, a statement is a transaction by default, and there are as many disk operations as there are pieces of data. Initializing 1,000 pieces of data requires 1,000 disk operations, which will repeatedly open and close the database 1,000 times, so the speed is full, and there is no guarantee that all data can be inserted at the same time.

The workaround is to use transaction processing.
(1)db.beginTransaction();//Manually set the start transaction

(2) db.setTransactionSuccessful();//Set the transaction processing successfully, if it is not set, it will be automatically rolled back and not submitted, and no database operation will be performed between setTransactionSuccessful and endTransaction

(3) db.endTransaction();//The processing is completed

In this way, SQLite will cache all the SQL statements to be executed in the memory first, and then write them to the database at one time when the commit is made. In this way, the database file is only opened and closed once, and the efficiency is greatly improved.

1. The transaction attribute is not used, and 1000 pieces of data are inserted

long startMillis = System.currentTimeMillis();
for(int i = 0; i < 1000; i++) {
    ContentValues val = new ContentValues();
    val.put(Student.NAME, "wgc"+i);
    val.put(Student.SCORE, "99");
    db.insert(Student.TABLE_NAME, null, values);
}
Log.v("transaction", "未开始事务属性之前总共耗时:" + (System.currentTimeMillis() - startMillis) + "");

2. Use transaction attributes to insert 1000 days of data

db.beginTransaction();
startMillis = System.currentTimeMillis();
for(int i = 0; i < 1000; i++) {
    ContentValues val = new ContentValues();
    val.put(Student.NAME, "wgc"+i);
    val.put(Student.SCORE, "99");
    db.insert(Student.TABLE_NAME, null, val);
}
db.setTransactionSuccessful();
db.endTransaction();
Log.v("transaction", "使用事务属性之后总共耗时:" + (System.currentTimeMillis() - startMillis) + "");

The following is a comparison result. It can be clearly seen that the efficiency is greatly improved after using the transaction attribute.

Three, Sqlite multi-threaded operation problems

We can know that SQLite is a file-level lock: multiple counties can read at the same time, but only one thread can write at the same time. If multiple threads read and write at the same time (here, different threads use different SQLiteDatabase instances), an exception such as android.database.sqlite.SQLiteException: database is locked will be encountered later.

The solution is to keep a single sqlite connection, keeping a single instance of SQLiteDatabase. Also add the synchronized keyword to all database operation methods.

1. Let's look at the consequences of a multi-threaded simultaneous write operation:

class WriteThread extends Thread{
        @Override
        public void run() {
            SQLiteDatabase db = openOrCreateDatabase("demo.db", MODE_PRIVATE, null);
            db.beginTransaction();
            for(int i = 0; i < 8000; i++) {
                ContentValues val = new ContentValues();
                val.put(Student.NAME, "wgc"+i);
                val.put(Student.SCORE, "99");
                db.insert(Student.TABLE_NAME, null, val);
            }
            db.setTransactionSuccessful();
            db.endTransaction();
            Log.v("multiThread2", "Thread ID:"+getId());
        }
    }
…………………..
    //开启5个线程执行写操作
        for(int i = 0; i < 5; i++) {
            new WriteThread().start();
        }

When you run the program, you will see that the program crashes and an error is reported. The error message is as follows:

2. Let's look at the consequences of a multi-threaded reading at the same time:

class ReadThread extends Thread {
        @Override
        public void run() {
            SQLiteDatabase db = openOrCreateDatabase("demo.db", MODE_PRIVATE,
                    null);
            for (int i = 0; i < 8000; i++) {
                StringBuilder builder = new StringBuilder();
                builder.append("select * from ");
                builder.append(Student.TABLE_NAME);
                builder.append(" where " + Student.NAME + "=?");

                Cursor cursor = db.rawQuery(builder.toString(),
                        new String[] { "wgc2" });
                Student student = new Student();
                if (cursor.moveToNext()) {
                    student.id = cursor.getString(cursor
                            .getColumnIndex(Student.ID));
                    student.name = cursor.getString(cursor
                            .getColumnIndex(Student.NAME));
                    student.score = cursor.getString(cursor
                            .getColumnIndex(Student.SCORE));
                }
                Log.v("multiThread",
                        "Thread ID:" + getId() + "===" + student.toString());
            }
        }
    }
…………………..
//开启5个线程执行读操作
for(int i = 0; i < 5; i++) {
    new ReadThread().start();
}

After the program runs, there is no exception and no error is reported.

The solution to multi-threaded simultaneous writing is given below:
(1) The first is to use the singleton mode, always maintain a connection, and use an instance of SQLiteDatabase.

public class SQLiteDatabaseManager {

    private static SQLiteDatabase db = null;


    public static SQLiteDatabase getInstance(Context context, String name, int mode) {
        if(db == null) {
            db = context.openOrCreateDatabase(name, mode, null);
        } 
        return db;
    }

}

The getInstance method of SQLiteDatabaseManager ensures that the same SQLiteDatabase instance is always used. Adding the synchronized keyword to the write function ensures that the method will not be called at the same time at the same time.

Then we made some changes to the code for the first multithreaded write operation:

private synchronized void write() {
        SQLiteDatabase db = SQLiteDatabaseManager.getInstance(
                getApplicationContext(), "demo.db", MODE_PRIVATE);

        db.beginTransaction();
        for (int i = 0; i < 8000; i++) {
            ContentValues val = new ContentValues();
            val.put(Student.NAME, "wgc" + i);
            val.put(Student.SCORE, "99");
            db.insert(Student.TABLE_NAME, null, val);
        }
        db.setTransactionSuccessful();
        db.endTransaction();
    }


        class WriteThread extends Thread {
        @Override
        public void run() {
            write();
        }
    }
private synchronized void read() {
        SQLiteDatabase db = SQLiteDatabaseManager.getInstance(
                getApplicationContext(), "demo.db", MODE_PRIVATE);

        for (int i = 0; i < 8000; i++) {
            StringBuilder builder = new StringBuilder();
            builder.append("select * from ");
            builder.append(Student.TABLE_NAME);
            builder.append(" where " + Student.NAME + "=?");

            Cursor cursor = db.rawQuery(builder.toString(),
                    new String[] { "wgc2" });
            Student student = new Student();
            if (cursor.moveToNext()) {
                student.id = cursor
                        .getString(cursor.getColumnIndex(Student.ID));
                student.name = cursor.getString(cursor
                        .getColumnIndex(Student.NAME));
                student.score = cursor.getString(cursor
                        .getColumnIndex(Student.SCORE));
            }
        }
    }

class ReadThread extends Thread {
        @Override
        public void run() {
            read();
        }
    }

We perform multi-threaded read and write operations again:

// 开启5个线程执行读操作
for (int i = 0; i < 5; i++) {
    new ReadThread().start();
}

// 开启5个线程执行写操作
for (int i = 0; i < 5; i++) {
    new WriteThread().start();
}

This time the program has no exceptions and no errors.

Source code download address:
http://download.csdn.net/detail/wen294299195/9308083

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325937030&siteId=291194637