android总结整理----Sqlite

  • Date:2015-4-23
  • Tag:android; sqlite; 事务; 多线程
  • Author:踏雪
  • Email:[email protected]

一、 Sqlite的基本操作—-增删改查

1、创建或打开数据库

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

2、创建或删除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、插入数据

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

4、修改数据

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

5、查询数据

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());
        }

二、Sqlite的事务属性

应用程序初始化时如果单独使用for+Insert的方式插入大量的数据,会导致应用响应慢。因为SQLite的数据库本质上是一个磁盘上的文件,所以一些的数据库操作其实就是对文件的操作。而频繁的文件操作是一个很耗时的过程,极大地影响了数据库的存储速度。

sqlite插入数据的时候默认一条语句就是一个事务,有多少条数据就有多少次磁盘操作。初始化1000条数据,也就要1000次磁盘的操作,将会重复的打开关闭数据库1000次,所以速度回满,而且还不能保证所有的数据都能同时插入。

解决方法是使用事务处理。
(1)db.beginTransaction();//手动设置开始事务

(2)db.setTransactionSuccessful();//设置事务处理成功,不设置会自动回滚不提交,在setTransactionSuccessful和endTransaction之间不进行任何数据库操作

(3) db.endTransaction();//处理完成

这样SQLite将把全部要执行的SQL语句先缓存到内存当中,然后等到commit的时候一次性写入到数据库。这样数据库文件只被打开关闭了一次,效率就大大提高。

1、未使用事务属性,插入1000条数据

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、使用事务属性,插入1000天数据

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) + "");

下面是一个对比结果,可以明显看出,使用事务属性后,效率大大提高了。

三、Sqlite的多线程操作问题

我们可以得知SQLite是文件级别的锁:多个县城可以同时读,但是同时只能只有一个线程写。如果多线程同时读写(这里指不同的线程使用的是不同的SQLiteDatabase实例),后面就会遇到android.database.sqlite.SQLiteException:database is locked这样的异常。

解决办法是保持一个sqlite连接,保持单个SQLiteDatabase实例。同时对所有数据库操作方法添加synchroned关键字。

1、 下面看一个多线程同时进行写操作的后果:

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();
        }

运行程序,会见到程序奔溃,并报错,错误提示如下:

2、 下面看一个多线程同时进行读的后果:

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();
}

程序运行后没有任何异常,也没有报错。

下面给出解决多线程同时写的解决方法:
(1) 首先是使用单例模式,始终保持一个连接,使用一个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;
    }

}

通过SQLiteDatabaseManager的getInstance方法就能保证始终使用同一个SQLiteDatabase实例。给write函数添加synchronized关键字能保证该方法统一时刻不会被同时调用。

然后我们队对第一次多线程写操作的代码做一些修改:

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();
        }
    }

我们再次进行多线程的读写操作:

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

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

这次程序就没有异常,也没有报错了。

源码下载地址:
http://download.csdn.net/detail/wen294299195/9308083

猜你喜欢

转载自blog.csdn.net/wen294299195/article/details/50085167