数据库的访问性能是很关键的问题,所以了解其底层实现,对于如何高效的使用接口函数非常有帮助。

 

SQLiteDatabase

    封装create、insert、delete、query、open、close这些数据库常用接口。SQLiteDatabase对象创建时就会调用jni dbopen去打开数据库文件,dbclose关闭数据库文件,打开与关闭时都会生成许多和释放辅助的结构,所以这是个费时的操作。

 

查询操作的结果集会缓存在内存中,合理的利用缓存能够提高程序的性能。因此在SQLiteDatabase的代码中可以看到,insert、delete操作只是略微包装,就直接去操作实际数据库文件了。但查询操作却先返回Cursor给用户,没有立即访问数据库数据,而是等到真正用户使用数据时才去将数据缓存到内存中。这里的内存也只是在Native空间中。

 

SQLiteDirectCursorDriver

    顾名思义,SQLiteDirectCursorDriver是个Cursor的驱动,让真的干活的家伙跑起来。SQLiteDatabase的Query时,SQLiteDirectCursorDriver创建一个SQLiteCursor对象返回给SQLiteDatabase。

 

SQLiteCursor

构造函数中并没有实质性的对数据库文件访问,真正产生数据集的操作是在getCount、onMove中调用fillWindow时发生。Query调用返回Cursor对象时,并没有真正的把结果集放到内存中,而只是把结果集对应的字段缓存到mColumns[]数组中。缓存字段会对SQLiteDatabase对象上锁,并且读取字段本身的操作也是有互斥机制保护,所以在select字段不变的情况下最好复用这个cursor对象。  

过程是异步的话,最好调用getCount之后再将Cursor对象返回给使用者,提高使用者线程对数据集访问的性能。

    getColumnIndex中会用一个map将columnName与columnIndex的映射保存起来,所以在应用程序中缓存字段索引的做法,不会性能有明显改进。

native_fill_window,这个函数可能会返回-1,表示查询操作没有完成(不知道这么什么情况下发生的)。如果该情况发生,SQLiteCursor会产生新的线程QueryThread去完成这次查询。真正将数据从数据库文件缓存到内存的工作,都是在fillWindow中做的。

只能够修改查询条件,就是where表达的过滤条件,在requery之前调用setSelectionArguments修改;如果过滤条件不变,则直接调用requery即可。requery中只是做变量的复位操作并更新jni层的查询条件。真正的将数据存入结果集的操作,要等到第一次调用getCount、onMove、moveToPosition操作。

 

 

CursorWindow

数据并没有复制到Java空间,而是保存Native空间,要用的时候才传上来。

 

SQLiteQuery

Java与C的交界处,SQLiteQuery封装对Query Jni的访问。成员函数fillWindow中调用jni native_fill_window,在C层将数据填到CursorWindow对象中。