###背景
最近在重构贴吧签到这个软件,一个比较头疼的模块就是数据库,因为涉及到保存贴吧帐号以及贴吧列表,大量的代码看起来简直是头疼,于是打算使用第三方数据库来进行重构.关于选择第三方库,尝试过两个,一个是 RealmgreenDAO.

机缘巧合的情况下,在一论坛里看到了 Realm,瞬间就被他代码的简洁所吸引了,所以首先我尝试的是Realm, 但至于为什么没有选择 Realm 以后再说,今天我们来说说 greenDao, 因为它完全符合我对数据库的所有幻想.

###开工 greenDao 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案.

ORM (Object Relational Mapping) 是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术

greenDao 使用 ORM, 将 JAVA 类与数据库表连接起来, 所以使用 greenDao, 我们可以不使用 SQLite 相关的代码, 仅几行代码就实现数据的增删改查. 相当简洁
first

举个栗子:   构造一个笔记类的数据存储类型

DaoMaster.DevOpenHelper do = new DaoMaster.DevOpenHelper(context, "AccountList.db", null);
SQLiteDatabase db = do.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
NoteDao noteDao = daoSession.getNoteDao();
Note note = new Note(null, noteText, comment, new Date());
noteDao.insert(note);
Log.d("DaoExample", "Inserted new note, ID: " + note.getId());

从创建数据库到插入日志就是这么简单. 插入仅需调用 insert方法既可.

接下来我们看看上述代码中出现的几个角色.

  • DaoMaster.DevOpenHelper

    先看看这个东西在源码里是什么:

      public static abstract class OpenHelper extends SQLiteOpenHelper {
    
          public OpenHelper(Context context, String name, CursorFactory factory) {
              super(context, name, factory, SCHEMA_VERSION);
          }
    
          @Override
          public void onCreate(SQLiteDatabase 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, CursorFactory factory) {
              super(context, name, factory); //greenDao在这里初始化数据库文件名
          }
    
          @Override
          public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
              Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
              dropAllTables(db, true);
              onCreate(db);
          }
      }
    

    从 greenDAO 的源码可知:DaoMaster.DevOpenHelper 继承于 SQLiteOpenHelper, 相信使用过 Android SQlite 的同学对SQLiteOpenHelper肯定不会感到陌生,一般在使用 SQLite 时会创建一个类来继承SQLiteOpenHelper 然后在创建表,执行数据库语句等等. 例如下面举个这个栗子,

    还是以 note 数据库来说明. 创建一个类继承于SQLiteOpenHelper,然后重写onCreateonUpgrade 方法, 如下面这段代码所示:

      public class MySQLiteHelper extends SQLiteOpenHelper {  
          //调用父类构造器  
          public MySQLiteHelper(Context context, String name, CursorFactory factory,  
                  int version) {  
              super(context, name, factory, 1);  
          }  
    
          /**
           * 当数据库首次创建时执行该方法,一般将创建表等初始化操作放在该方法中执行.
           * 重写onCreate方法,调用execSQL方法创建表
           * */  
          @Override  
          public void onCreate(SQLiteDatabase db) {  
            db.execSQL("CREATE TABLE " + "IF NOT EXISTS " + "\"NOTE\" (" + //
                        "\"_id\" INTEGER PRIMARY KEY ," + // 0: id
                        "\"TEXT\" TEXT NOT NULL ," + // 1: text
                        "\"COMMENT\" TEXT," + // 2: comment
                        "\"DATE\" INTEGER);"); // 3: date
    
          }  
    
          //当打开数据库时传入的版本号与当前的版本号不同时会调用该方法  
          @Override  
          public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                /* upgrade your database */
          }  
    
      }  
    

    从上述两个代码段来看,greenDAO 确实是基于 SQLite 的一个 ORM 数据库第三方库. 只不过是DaoMaster帮你创建了数据库的表,而这些表的参数就是note 类的变量.

  • DaoMaster
    DaoMaster 是使用 greenDao 的切入点, 它掌管着数据库对象(SQLiteDatabase) 并且它还管理所有的 DAO 类,例如上面的 NoteDao, 它有一些静态方法,例如:
    创建数据库表

      /** Creates underlying database table using DAOs. */
      public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
          NoteDao.createTable(db, ifNotExists);
      }
    

    删除数据库表

      /** Drops underlying database table using DAOs. */
      public static void dropAllTables(SQLiteDatabase db, boolean ifExists) {
          NoteDao.dropTable(db, ifExists);
      }
    

    而且上面所说的DaoMaster.DevOpenHelper 也是其一个内部类, 所以可以看出DaoMaster 是站在greenDao 的最高峰的.

  • DaoSession
    DaoSession 管理着所有的DAO 对象, 例如它会有这样的成员变量:

      private final NoteDao noteDao;
    

    你可以通过 getNoteDao 方法来获取这个变量, 在 DaoSession.java 里的方法很少,除了构造函数就是 Dao object 的 getter 了,但 DaoSession 是继承于 AbstractDaoSession 的,看看AbstractDaoSession的部分源码:

      public class AbstractDaoSession {
          private final SQLiteDatabase db;
          private final Map<Class<?>, AbstractDao<?, ?>> entityToDao;
    
          public AbstractDaoSession(SQLiteDatabase db) {
              this.db = db;
              this.entityToDao = new HashMap<Class<?>, AbstractDao<?, ?>>();
          }
    
          protected <T> void registerDao(Class<T> entityClass, AbstractDao<T, ?> dao) {
              entityToDao.put(entityClass, dao);
          }
    
          /** Convenient call for {@link AbstractDao#insert(Object)}. */
          public <T> long insert(T entity) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
              return dao.insert(entity);
          }
    
          /** Convenient call for {@link AbstractDao#insertOrReplace(Object)}. */
          public <T> long insertOrReplace(T entity) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
              return dao.insertOrReplace(entity);
          }
    
          /** Convenient call for {@link AbstractDao#refresh(Object)}. */
          public <T> void refresh(T entity) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
              dao.refresh(entity);
          }
    
          /** Convenient call for {@link AbstractDao#update(Object)}. */
          public <T> void update(T entity) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
              dao.update(entity);
          }
    
          /** Convenient call for {@link AbstractDao#delete(Object)}. */
          public <T> void delete(T entity) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
              dao.delete(entity);
          }
    
          /** Convenient call for {@link AbstractDao#deleteAll()}. */
          public <T> void deleteAll(Class<T> entityClass) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entityClass);
              dao.deleteAll();
          }
    
          /** Convenient call for {@link AbstractDao#load(Object)}. */
          public <T, K> T load(Class<T> entityClass, K key) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, K> dao = (AbstractDao<T, K>) getDao(entityClass);
              return dao.load(key);
          }
    
          /** Convenient call for {@link AbstractDao#loadAll()}. */
          public <T, K> List<T> loadAll(Class<T> entityClass) {
              @SuppressWarnings("unchecked")
              AbstractDao<T, K> dao = (AbstractDao<T, K>) getDao(entityClass);
              return dao.loadAll();
          }
      }
    

    AbstractDaoSession 加入了一些通用的持久性的方法,例如插入,更新,删除等等操作. 所以我们也可以通过 daoSession.insert(note) 来插入一条note.

  • DAOS DAOS 是直接和数据库打交道的, 例如,DAOS 里生成数据库语句, 将成员变量与表里的参数绑定对应起来, 并且在它的父类AbstractDao 里实现了相对DaoSession更多的操作数据的方法, 也可以从上面DaoSession 父类的源码里了解到,DaoSession 的那些方法实际上就是对DAOS 的一层封装: 例如insert 操作实际上还是调用的 DAOS的 insert

       /** Convenient call for {@link AbstractDao#insert(Object)}. */
       public <T> long insert(T entity) {
          @SuppressWarnings("unchecked")
          AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass());
          eturn dao.insert(entity);
       }
    

    他们的关系可以总结如下图所示 sec

    相信通过上面的描述,大家大概对 GreenDAO 有了一定的了解. 接下来,我们再来深入的认识它吧~~~

    采用注册的方式将 Master 与所有的 DAOS的 DAOConfig(这个需要重点讲一下) 绑定, 使用SQLiteStatement

    未完待续…