您的位置:首页 > 移动开发 > Android开发

Android之Sqlite开发中可能被你忽视的细节

2016-10-28 17:21 274 查看

概述

Sqlite是在Android日常开发中使用的还是比较频繁的。有的同学可能会说:“我平时用的就不多”。一种情况是你用的第三方的开源库比如realm,或者是ORM型的GreenDao等,甚至有的还用了key-value形式的Snappy DB。另一种情况确实是开发中数据库用的少,但是这种情况很少。我们用Sqlite可能很熟练,但是对于一些细节,可能做了很长时间开发的同学有好多细节的地方还是不知道的。

关于Android中Sqlite使用的一些细节

1、对于数据的批量插入,数据的修改与删除建议加上事务。

使用事务可以保证每次事务操作的原子性。除此之外,有人做过测试,批量插入1000条数据的时候,使用事务和不使用事务的差别很大。使用事务的批量插入效率比不使用事务的批量插入要高的多。出现错误自动回滚。关于增加事务能够提升批量插入的速度,感觉很奇怪。事务是具有 的机制的(比如悲观锁乐观锁),我们都知道synchronized的操作相对于不加synchronized的操作效率低的。所以有点不理解,不过经过测试,确实在批量插入的时候,加上事务,批量插入的效率高的多。

事务事例:

public void insertStudent(Student student){
if (student == null){
return;
}
SQLiteDatabase database = null;
try {
database = dbHelper.getReadableDatabase();
database.beginTransaction();//开启事务
ContentValues cv = new ContentValues();
cv.put(StudentColumn.NAME,student.getName());
cv.put(StudentColumn.SEX,student.getSex());
cv.put(StudentColumn.STUDENT_NUM,student.getStudentNum());
database.insertOrThrow(TableHelpter.TB_STUDENT,null,cv);
database.setTransactionSuccessful(); //操作执行完成将事务设置成功,这一句必须要有。否则的话,在关闭事务的时候会回滚结果不提交。
}catch (Exception e){
e.printStackTrace();
} finally {
database.endTransaction();//数据库关闭前关闭事务
if (database != null){
database.close();
}
}
}


2、索引的使用。如果应用中查询操作量级较大,业务对要求查询要求较高的可以使用索引。

其他情况不要轻易使用。因为事物都有两面。

①、对于数据的增删改,索引会降低增删改的效率,使用了索引会变慢,比如你想要删除字典中的一个字,那么你同时也需要删除这个字在拼音索引和部首索引中的信息。

②、建立索引会增加数据库的大小,比如字典中的拼音索引和部首索引实际上是会增加字典的页数,让字典变厚的。

3、大批量数据的插入或者删除的时候尽量开启新的线程

数据量过大,在插入或者查询的时候耗时就会比较大。如果在UI线程中执行容易出现ANR。

4、SQLiteDatabase的引用

在多线程中只使用一个SQLiteDatabase引用,在用SQLiteDataBase.close()的时需要注意调是否还有别的线程在使用这个实例。如果一个线程操作完成后就直接close了,别一个正在使用这个数据库的线程就会异常。

解决办法:

①、将SQLiteDatabase实例放在Application中,使其生命周期和App一致。

②、采用计数器的方式,在Application中添加一个线程安全的计数器,每次数据库操作完成后检查一下计数是否为0。为0就关闭SQLiteDatabase,不为0就不关闭。

5、数据查询时对cursor的遍历

遍历cursor时,我们通常的做法是这样:

private void badQueryWithLoop(SQLiteDatabase db) {
Cursor cursor = db.query(TableDefine.TABLE_RECORD, new String[]{TableDefine.COLUMN_INSERT_TIME}, null, null, null, null, null) ;
while (cursor.moveToNext()) {
long insertTime = cursor.getLong(cursor.getColumnIndex(TableDefine.COLUMN_INSERT_TIME));
}
}


如果我们将获取ColumnIndex的操作提到循环之外,效果会更好一些

private void goodQueryWithLoop(SQLiteDatabase db) {
Cursor cursor = db.query(TableDefine.TABLE_RECORD, new String[]{TableDefine.COLUMN_INSERT_TIME}, null, null, null, null, null) ;
int insertTimeColumnIndex = cursor.getColumnIndex(TableDefine.COLUMN_INSERT_TIME);
while (cursor.moveToNext()) {
long insertTime = cursor.getLong(insertTimeColumnIndex);
}
cursor.close();
}


6、ContentValues容量调整

ContentValues内部采用了HashMap来存储Key-Value数据,ContentValues的初始容量是8,如果当添加的数据超过8之前,则会进行双倍扩容操作,因此建议对ContentValues填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐