greendao的使用

以前开发用到数据库时,基本上都是用android原生的sql语句,写那些语句时稍有不慎,就给你抛出一个exception。现在网上有很多的数据库ORM框架,今天写篇文章来记录一下比较好用的框架:greendao的使用。关于greendao的介绍,网上已经有很多了,可以自行查阅。


准备工作

  • 1、新建一个android工程,在main目录下新建一个文件夹java-gen,如下图:
QQ20160305-0@2x.png
  • 2、在同一个project下,再新建一个java module,并新创建一个类,如下图:
QQ20160305-1@2x.png
  • 3、在android module中的build.gradle文件中加上以下代码:

    sourceSets {    
          main {        
                    java.srcDirs = ['src/main/java',  'src/main/java-gen']    
          }
    }
    
    compile 'de.greenrobot:greendao:2.1.0'
    
QQ20160305-2@2x.png

在java module中的build.grade文件中添加以下代码:

  compile 'de.greenrobot:greendao-generator:2.1.0'

自动生成数据库Bean和Dao类

以下是java module中类的实现

  public class GreenDaoGeneratorTest {
      //自动生成类的包名  
      public static String PACKAGE_NAME = "com.blainpeng.greendao"; 
      //这里的OUT_DIR就是我们新建的java-gem的路径     
      public static String OUT_DIR = "/Users/Desktop/AndroidProject/GreenDaoDemo/app/src/main/java-gen";    
      public static void main(String[] args) throws Exception {        
      // 1、创建一个用于添加实体(entity)的模式(Schema)对象      
      Schema schema = new Schema(1, PACKAGE_NAME); //第一个参数为数据库的版本号 
       // Schema schema = new Schema(2, PACKAGE_NAME);版本号升级
      // 2、获得了Schema对象后就可以添加实体了,也就是添加数据库表了。   
        addCustomer(schema);      
      // 3、利用DaoGenerator类生成代码,并将自动生成的代码放到指定的目录       
        new DaoGenerator().generateAll(schema, OUT_DIR);    
      }
        
      private static void addCustomer(Schema schema) {
      // 4、一个实体类就关联到数据库中的一张表,此处表名为:Customer         
        Entity entity = schema.addEntity("Customer");         
      // 5、设置数据库表中的字段(greenDao会自动根据实体类的属性来创建表字段,并赋予默认值)       
        entity.addIdProperty().autoincrement();            
        entity.addStringProperty("name").notNull();            
        entity.addStringProperty("age").notNull();        
        entity.addStringProperty("phone").notNull();        
        entity.addStringProperty("marriage").notNull();          
        //entity.addStringProperty("address");  升级时添加的新列名  
      }
}

写好这个类以后,点击它,右击run ,出现下图说明运行成功:

QQ20160305-3@2x.png

此时,java-gen文件夹里面就有4个类了。


如何调用?

  • 创建一个类继承自Application,上代码:

      public class BaseApplication extends Application {    
          public static DaoMaster                daoMaster;    
          public static DaoSession               daoSession;   
          public static SQLiteDatabase           db;    
          public static DaoMaster.DevOpenHelper  helper;    
          @Override    
          public void onCreate()    {        
              super.onCreate();     
         /*       
          * 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 
            SQLiteOpenHelper 对象       
          */        
        helper = new DaoMaster.DevOpenHelper(this, "dbname.db", null);        
        db = helper.getWritableDatabase();        
        daoMaster = new DaoMaster(db);        
        daoSession = daoMaster.newSession();       
        }    
        public static DaoSession getDaoSession()    {        
            return daoSession;    
        }    
        public static SQLiteDatabase getSqLiteDatabase()    {        
            return db;    
        }
    }
    
  • 在activity中调用

    //先获得dao的实例
    customerDao = BaseApplication.getDaoSession().getCustomerDao();
    //创建对象,并将对象添加到数据库
    Customer customer = new Customer(null, name, age, phone,marriage);
    customerDao.insert(customer);
    
    //查询方法
    list = customerDao.loadAll();
    

使用greendao,对于数据库的CRUD,我们只需要往里面添加一个对象就可以了,再也不需要去记那些spl语句子,是不是非常爽啊。


如何安全地升级数据库?

  • 数据库升级的原理
    先创建一个新表,将原表中的数据进行复制,再把原数据库表删掉

      // 删除表时,使用事务处理,使得修改能立即更新到数据库文件中
      db.beginTransaction();
      try
      {
          // 重命名数据库表
          String tempTableName = TABLE_NAME + "_temp";
          String sql = "ALTER TABLE " + TABLE_NAME + " RENAME TO " + tempTableName;
          db.execSQL(sql);
    
          // 创建一个新的数据库表
          db.execSQL(sql_create_table2);
    
          // 将数据从tempTableName中插入到TABLE_NAME表中
          sql = "INSERT INTO " + TABLE_NAME + " SELECT *," + " ''FROM " + tempTableName;
          db.execSQL(sql);
    
          // 删除临时表 
          sql = "DROP TABLE " + tempTableName;
          db.execSQL(sql);
          db.setTransactionSuccessful();
      }
      finally
      {
          db.endTransaction();
      }
    
  • 使用greendao时进行数据库升级
    以下是一位国外大神的封装:

    public class MigrationHelper{
    
      private static final String    CONVERSION_CLASS_NOT_FOUND_EXCEPTION   = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
      private static MigrationHelper instance;
      public static MigrationHelper getInstance()
      {   
        if (instance == null)   {      
            instance = new MigrationHelper();   
        }   
        return instance;
      }
       /** 
          * 数据迁移 
          *  
          * @param db 
          * @param daoClasses 
          */
            public void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses){
              generateTempTables(db, daoClasses);// 删除旧的数据库表
              DaoMaster.dropAllTables(db, true);// 重新创建新的数据库表
              DaoMaster.createAllTables(db, false);restoreData(db, daoClasses);
            }
          /** 
            * 生成临时数据库表 
            *  
            * @param db 
            * @param daoClasses 
            */
       private void generateTempTables(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses){
             for (int i = 0; i < daoClasses.length; i++){
                  DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
                  String divider = "";
                  String tableName = daoConfig.tablename;
                  String tempTableName = daoConfig.tablename.concat("_TEMP");
                  ArrayList<String> properties = new ArrayList<>();
                  StringBuilder createTableStringBuilder = new StringBuilder();
                  createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
                  for (int j = 0; j < daoConfig.properties.length; j++){
                      String columnName = daoConfig.properties[j].columnName;
                      if (getColumns(db, tableName).contains(columnName)){
                          properties.add(columnName);
                          String type = null;
                          try{
                                type = getTypeByClass(daoConfig.properties[j].type);
                              }catch (Exception exception){
                                exception.printStackTrace();
                              }
                              createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
                              if (daoConfig.properties[j].primaryKey){
                                  createTableStringBuilder.append(" PRIMARY KEY");
                              }
                              divider = ",";
                        }
                    }
                    createTableStringBuilder.append(");");
                    db.execSQL(createTableStringBuilder.toString());
                    StringBuilder insertTableStringBuilder = new StringBuilder();
                    insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
                    insertTableStringBuilder.append(TextUtils.join(",", properties));
                    insertTableStringBuilder.append(") SELECT ");
                    insertTableStringBuilder.append(TextUtils.join(",", properties));
                    insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
                    db.execSQL(insertTableStringBuilder.toString());
                }
             }
      /** 
         * 保存数据 
         *  
         * @param db 
         * @param daoClasses 
         */
      private void restoreData(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses){ 
        for (int i = 0; i < daoClasses.length; i++){
              DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
              String tableName = daoConfig.tablename;
              String tempTableName = daoConfig.tablename.concat("_TEMP");
              ArrayList<String> properties = new ArrayList<String>();
              for (int j = 0; j < daoConfig.properties.length; j++){
                    String columnName = daoConfig.properties[j].columnName;
                    if (getColumns(db, tempTableName).contains(columnName)){
                        properties.add(columnName);
                     }
               }
          StringBuilder insertTableStringBuilder = new StringBuilder();
          insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
          insertTableStringBuilder.append(TextUtils.join(",", properties));
          insertTableStringBuilder.append(") SELECT ");
          insertTableStringBuilder.append(TextUtils.join(",", properties));
          insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
          StringBuilder dropTableStringBuilder = new StringBuilder();
          dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
          db.execSQL(insertTableStringBuilder.toString());
          db.execSQL(dropTableStringBuilder.toString());
        }
      }
    /** 
       *  获得数据库表字段类型 
       *  
       * @param type 
       * @return 
       * @throws Exception 
       */
        private String getTypeByClass(Class<?> type) throws Exception{
          if (type.equals(String.class)) { return "TEXT"; }
          if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) { return "INTEGER"; }
          if (type.equals(Boolean.class)) { return "BOOLEAN"; }
          Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));   
          exception.printStackTrace();   
          throw exception;
        }
        /** 
           * 获得数据库所有列 
           *  
           * @param db 
           * @param tableName 
           * @return 
           */
      private static List<String> getColumns(SQLiteDatabase db, String tableName){
        List<String> columns = new ArrayList<>();
        Cursor cursor = null;
        try{
              cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
              if (cursor != null){
                  columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
              }
        }catch (Exception e){
              Log.v(tableName, e.getMessage(), e);
              e.printStackTrace();
         }
        finally{
            if (cursor != null) cursor.close();
        }
        return columns;
      }
    }
    
  • 最后在DaoMaster的onUpgrade内调用这个帮助类中的方法
    MigrationHelper.getInstance().migrate(db, CustomerDao.class);
    好了,greendao的使用就这么多了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容