Ormlite性能优化总结
该篇博客会对ormlite的性能优化做一些总结,包括使用ormlite的config文件、WAL、以及一些性能优化总结点。
一、使用ormlite的config文件
使用ormlite_config文件来创建数据库和dao,可以减少初始化数据库的开销。
1.原理
ormlite的数据库创建会调用TableUtils.createTableIfNotExists(connectionSource, LaunchAdEO.class);方法,其中又会调用到
1 | private static <T, ID> int createTable(ConnectionSource connectionSource, Class<T> dataClass, boolean ifNotExists) |
在其中的DaoManager.createDao(connectionSource, dataClass)方法中会进行dao创建,其中的逻辑是先会调用到DaoManager的createDaoFromConfig方法,如果返回值不为null,那么就会直接返回,否则会通过耗时的反射来创建dao。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* Creates the DAO if we have config information cached and caches the DAO.
*/
private static <D, T> D createDaoFromConfig(ConnectionSource connectionSource, Class<T> clazz) throws SQLException {
// no loaded configs
if (configMap == null) {
return null;
}
@SuppressWarnings("unchecked")
DatabaseTableConfig<T> config = (DatabaseTableConfig<T>) configMap.get(clazz);
// if we don't config information cached return null
if (config == null) {
return null;
}
// else create a DAO using configuration
Dao<T, ?> configedDao = doCreateDao(connectionSource, config);
@SuppressWarnings("unchecked")
D castDao = (D) configedDao;
return castDao;
}
那么这里的configMap又是在哪里被填充进去的呢?
搜索代码发现是在DaoManager的addCachedDatabaseConfig中完成的,而该方法是在OrmLiteSqliteOpenHelper的构造函数。
1 | public OrmLiteSqliteOpenHelper(Context context, String databaseName, SQLiteDatabase.CursorFactory factory, int databaseVersion, |
或者
1 | public OrmLiteSqliteOpenHelper(Context context, String databaseName, SQLiteDatabase.CursorFactory factory, int databaseVersion, |
中完成的调用,该构造函数会调用到下面的代码,也就是在构造函数中完成配置文件的读取,并最终生成DatabaseTableConfig的对象
1 | BufferedReader reader = new BufferedReader(new InputStreamReader(stream), 4096); |
总结:ormlite,在调用openHelper时,如果不传入配置文件,会默认使用耗时的反射来定义数据库的名称和字段
2.如何生成配置文件
在官方文档[1]的提示下,在类OrmliteConfigUtil的方法writeConfigForFile
1 | public class DatabaseConfigUtil extends OrmLiteConfigUtil { |
中会调用到OrmliteConfigUtil的writeConfigForTable方法。
该方法会扫描所有的.java文件,效率比较差,我们可以给出需要写入config文件中的java类名。
1 | public class DatabaseConfigUtil extends OrmLiteConfigUtil { |
当我们运行完上述工具类,我们就会在raw resource folder下面得到config文件,同时,也会生成R.java文件,这样我们就可以在用
1 | public OrmLiteSqliteOpenHelper(Context context, String databaseName, SQLiteDatabase.CursorFactory factory, int databaseVersion, |
构造函数中传入R.raw.ormlite_config这个configFileld参数。
按照[2]进行操作,
但注意出现了类似错误Exception in thread “main” java.lang.ClassNotFoundException: my.package.DatabaseConfigUtil
如何解决?
首先我们得在app/src/main/res/raw/ 创建文件,因为我们在DBHHelper的构造函数中已经引入了R.raw.ormlite_config了
然后Edit Configuration中的before launch中去掉make
在Working directory中进行$MODULE_DIR$/src/main的配置
同时我们需要compile project(‘:ormlite’) 也就是编译包含DatabaseConfigUtil的项目,这点非常重要
在writeConfigFile(“ormlite_config.txt”, classes);时直接写出ormlite文件即可。
如果还是出现Exception in thread “main” java.lang.ClassNotFoundException错误,可以考虑将配置删除以后,再运行并更改配置。
二、一些tips
1.将数据库的任何操作放在启动页之后来进行,防止在启动页中由于调用到了getWritableDatabase()方法来进行耗时的数据库初始化以及更新操作。
2.ormlite使用批处理,包括dao.callbatchtasks,或者直接使用TransactionManager.callInTransaction。其中dao.callbatchtasks在内部也是调用callInTransaction的。
3.
SQLite日志[6][8]
开启
1 | adb shell setprop log.tag.SQLiteLog V |
上述语句也可单独使用 其中第三条更有用一些 代表打印时间
并且需要杀掉进程重启
关闭 注意这里为中文的双引号
1 | adb shell setprop log.tag.SQLiteLog “” |
4.复杂的实体数据,可以考虑使用executeRaw来执行原生sql
getDao().executeRaw()
5.增加数据库cache,在插入或者更新数据后,将数据保存在内存中,下次只要从内存中取即可。
6.直接使用cursor减少不必要的映射。
1 | public Cursor getCursorOfAll() { |
参考文献
[1]http://ormlite.com/javadoc/ormlite-core/doc-files/ormlite_4.html#Config-Optimization
[2]http://stackoverflow.com/questions/17298773/android-studio-run-configuration-for-ormlite-config-generation
[3]https://www.sqlite.org/wal.html
[4]http://stackoverflow.com/questions/34059173/exception-write-ahead-logging-wal-mode-cannot-be-enabled-or-disabled-while-th
[5]http://stackoverflow.com/questions/12909489/ormlite-performance-on-4-0-3-ics
[6]http://blog.chengyunfeng.com/?p=583
[7]https://www.sqlite.org/wal.html
[8]http://stackoverflow.com/questions/29022059/log-query-time-in-sqlite-on-android