android总结整理----Sqlite
- Date:2015-4-23
- Tag:android; sqlite; 事务; 多线程
- Author:踏雪
- Email:shuwoom.wgc@gmail.com
一、 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
更多相关文章
- 【Android学习系列】android Content Provider 应用步骤
- android listview的创建及行删除操作
- Android(安卓)intent数据传递
- Android(安卓)9.0 Launcher启动详解
- android百度地图(二)之定位
- Android中的数据库——SQLite
- 你真的会用Android的Dialog吗?由一个Exception想到的
- Sqlite3 增删改查操作实例
- Android(安卓)ListView实现通讯录的例子