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

概述

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填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作。

你可能感兴趣的:(sqlite,事务,database,SQLite性能优化)