关于greenDao
简介
greenDAO 是一个开源的ORM数据库框架。它帮助开发者从日常的数据库的读写sql语句中解放出来,开发者只需要关注具体的Java对象,就能够进行数据库的访问操作。
greenDao features
1.强大的性能,可能是ORM数据库中性能最好的。官方把greenDao和OrmLite、ActiveAndroid做的性能对比,数据如下:
- 易于使用的API
- 低内存消耗
- 包size比较小,如果不包含加密,大概proguard后的包size为8k。
- 支持数据库加密: 支持SQLCipher。SQLCipher对个人开发者来说倒不错,不过对于公司来说吸引力不大。
greenDao 核心类说明
如上图所示,greenDao有几个核心类:
- DaoMaster : db的管理类,是db的总入口,总管的角色,管理着database创建、更新以及数据库中有哪些表之类。每一个db对应一个DaoMaster。
- DaoSession : 会话, 管理指定的schema的所有dao,另外DaoSession也支持数据缓存,可以指定dao是否使用缓存。
- xxxDao : 某个table的操作对象
- Entity : 通俗易懂,不解释了
greenDao工程说明
greenDao 的github包含两个公共组件 :
- DaoCore :greenDao的核心框架,我们一般说的greenDao就是指这个
- DaoGenerator :通俗易懂,就是xxxDao的生成器,帮助开发者生成xxxDAO对象,开发者只需要定义自己的Entity,通过DaoGenrator就能够生成对应的xxxDao对象。
新手接入
这里演示一个学生的例子
1.创建自己的Android Project,前戏就不贴了
2.导入greenDao
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
}
}
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile 'org.greenrobot:greendao:3.2.0'
}
3.编写Entity
我们定义一个Student class:
@Entity
public class Student {
@Id
private String mId;
private String mName;
private int mGender;
}
@Entity和@Id是greenDao的标签,分别用来表示这是个Entity以及Entity的主键,greenDao Generator会根据这些标签自动生成DaoMaster、DaoSession、StudentDao。 具体的标签的使用方法可以查看官方文档。
4、点击Run, 最后生成的代码如下(部分加了注释):
DaoMaster.java
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* Master of DAO (schema version 1): knows all DAOs.
*/
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 1;
/** Creates underlying database table using DAOs. */
public static void createAllTables(Database db, boolean ifNotExists) {
StudentDao.createTable(db, ifNotExists);
}
/** Drops underlying database table using DAOs. */
public static void dropAllTables(Database db, boolean ifExists) {
StudentDao.dropTable(db, ifExists);
}
/**
* WARNING: Drops all table on Upgrade! Use only during development.
* Convenience method using a {@link DevOpenHelper}.
*/
public static DaoSession newDevSession(Context context, String name) {
Database db = new DevOpenHelper(context, name).getWritableDb();
DaoMaster daoMaster = new DaoMaster(db);
return daoMaster.newSession();
}
public DaoMaster(SQLiteDatabase db) {
this(new StandardDatabase(db));
}
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
registerDaoClass(StudentDao.class);
}
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
/**
* Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
*/
public static abstract class OpenHelper extends DatabaseOpenHelper {
public OpenHelper(Context context, String name) {
super(context, name, SCHEMA_VERSION);
}
public OpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory, SCHEMA_VERSION);
}
@Override
public void onCreate(Database db) {
Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
//创建数据库
createAllTables(db, false);
}
}
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
//数据库升级。。。非常霸道,直接清除表后重建,我们实际项目中肯定不会这么使用的
dropAllTables(db, true);
onCreate(db);
}
}
}
DaoSession.java :
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* {@inheritDoc}
*
* @see org.greenrobot.greendao.AbstractDaoSession
*/
public class DaoSession extends AbstractDaoSession {
private final DaoConfig studentDaoConfig;
private final StudentDao studentDao;
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap) {
super(db);
studentDaoConfig = daoConfigMap.get(StudentDao.class).clone();
//设置缓存类型
studentDaoConfig.initIdentityScope(type);
studentDao = new StudentDao(studentDaoConfig, this);
registerDao(Student.class, studentDao);
}
//清除缓存
public void clear() {
studentDaoConfig.clearIdentityScope();
}
public StudentDao getStudentDao() {
return studentDao;
}
}
StudentDao.java
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* DAO for table "STUDENT".
*/
public class StudentDao extends AbstractDao<Student, String> {
public static final String TABLENAME = "STUDENT";
/**
* 定义Studnet表的Column
*/
public static class Properties {
public final static Property MId = new Property(0, String.class, "mId", true, "M_ID");
public final static Property MName = new Property(1, String.class, "mName", false, "M_NAME");
public final static Property MGender = new Property(2, int.class, "mGender", false, "M_GENDER");
}
public StudentDao(DaoConfig config) {
super(config);
}
public StudentDao(DaoConfig config, DaoSession daoSession) {
super(config, daoSession);
}
/** 创建Student表,这种创建方法有点太low了居然i无法做到自动创建 */
public static void createTable(Database db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"STUDENT\" (" + //
"\"M_ID\" TEXT PRIMARY KEY NOT NULL ," + // 0: mId
"\"M_NAME\" TEXT," + // 1: mName
"\"M_GENDER\" INTEGER NOT NULL );"); // 2: mGender
}
/** Drops the underlying database table. */
public static void dropTable(Database db, boolean ifExists) {
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"STUDENT\"";
db.execSQL(sql);
}
/**
* 插入语句时绑定的数据,这种写法有点坑,万一MId为空时,生成的语句就有w
*/
@Override
protected final void bindValues(DatabaseStatement stmt, Student entity) {
stmt.clearBindings();
String mId = entity.getMId();
if (mId != null) {
stmt.bindString(1, mId);
}
String mName = entity.getMName();
if (mName != null) {
stmt.bindString(2, mName);
}
stmt.bindLong(3, entity.getMGender());
}
@Override
protected final void bindValues(SQLiteStatement stmt, Student entity) {
stmt.clearBindings();
String mId = entity.getMId();
if (mId != null) {
stmt.bindString(1, mId);
}
String mName = entity.getMName();
if (mName != null) {
stmt.bindString(2, mName);
}
stmt.bindLong(3, entity.getMGender());
}
@Override
public String readKey(Cursor cursor, int offset) {
return cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0);
}
/**
* 从sql读取数据,生成student对象
*/
@Override
public Student readEntity(Cursor cursor, int offset) {
Student entity = new Student( //
cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0), // mId
cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // mName
cursor.getInt(offset + 2) // mGender
);
return entity;
}
@Override
public void readEntity(Cursor cursor, Student entity, int offset) {
entity.setMId(cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0));
entity.setMName(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
entity.setMGender(cursor.getInt(offset + 2));
}
@Override
protected final String updateKeyAfterInsert(Student entity, long rowId) {
return entity.getMId();
}
@Override
public String getKey(Student entity) {
if(entity != null) {
return entity.getMId();
} else {
return null;
}
}
@Override
public boolean hasKey(Student entity) {
return entity.getMId() != null;
}
@Override
protected final boolean isEntityUpdateable() {
return true;
}
}
5.使用
- 初始化数据库
DevOpenHelper helper = new DevOpenHelper(this, "students");
Database db = helper.getWritableDb();
mDaoSession = new DaoMaster(db).newSession();
mStudentDao = mDaoSession.getStudentDao();
- 添加
Student student = new Student();
student.setMId(String.valueOf(System.currentTimeMillis()));
student.setMName("name"+System.currentTimeMillis());
student.setMGender((int) (System.currentTimeMillis()%2));
mStudentDao.insert(student);
- 删除
final Student deleteStudent = mStudentDao.queryBuilder().orderDesc(StudentDao.Properties.MId).limit(1).unique();
mStudentDao.delete(deleteStudent);
小结
从上面的demo,可以看到访问数据库的过程变得非常的简单。开发者只需要定义自己的entity,greenDao Generator就能自动生成对应的类文件。整个使用过程非常简单,但是,一般说到但是,就是来讲它的坏话了。。。我们也看到greenDao有如下几个问题:
- greenDao Generator仍然有点笨,生成的代码真心是笨(如:要是我们的变量是以m开头,则会生成 getM,setM方法。),还需要我们进一步加工,才能变成比较美观的代码。
- greenDao的DaoMaster在数据库的创建以及更新上都使用了指定sql语句的方法,比较笨拙,虽然网上有一个叫做MigrationHelper的解决方案,但仍不够友好。后续再给大家介绍一下我们使用的方法。
- xxxDao的Property支持的属性有限
如:Property.java
public final int ordinal;
public final java.lang.Class<?> type;
public final java.lang.String name;
public final boolean primaryKey;
public final java.lang.String columnName;
不支持default、is null、unique 等属性
Reference: https://github.com/greenrobot/greenDAO