Android框架之路——GreenDao3.2.2的使用

CSDN同步更新:http://blog.csdn.net/bskfnvjtlyzmv867/article/details/71250101

一、簡(jiǎn)介

GreenDAO是一個(gè)開源的安卓ORM框架,能夠使SQLite數(shù)據(jù)庫(kù)的開發(fā)再次變得有趣。它減輕開發(fā)人員處理低級(jí)數(shù)據(jù)庫(kù)需求,同時(shí)節(jié)省開發(fā)時(shí)間。 SQLite是一個(gè)令人敬畏的內(nèi)嵌的關(guān)系數(shù)據(jù)庫(kù),編寫SQL和解析查詢結(jié)果是相當(dāng)乏味和耗時(shí)的任務(wù)。通過(guò)將Java對(duì)象映射到數(shù)據(jù)庫(kù)表(稱為ORM,“對(duì)象/關(guān)系映射”),GreenDAO可以將它們從這些映射中釋放出來(lái),這樣,您可以使用簡(jiǎn)單的面向?qū)ο蟮腁PI來(lái)存儲(chǔ),更新,刪除和查詢數(shù)據(jù)庫(kù)。

簡(jiǎn)單的講,GreenDAO 是一個(gè)將對(duì)象映射到 SQLite 數(shù)據(jù)庫(kù)中的輕量且快速的 ORM 解決方案。

<p>

</p>

二、ORM概念

對(duì)象-關(guān)系映射(OBJECT/RELATIONALMAPPING,簡(jiǎn)稱ORM),是隨著面向?qū)ο蟮能浖_發(fā)方法發(fā)展而產(chǎn)生的。用來(lái)把對(duì)象模型表示的對(duì)象映射到基于SQL的關(guān)系模型數(shù)據(jù)庫(kù)結(jié)構(gòu)中去。這樣,我們?cè)诰唧w的操作實(shí)體對(duì)象的時(shí)候,就不需要再去和復(fù)雜的 SQL 語(yǔ)句打交道,只需簡(jiǎn)單的操作實(shí)體對(duì)象的屬性和方法。ORM 技術(shù)是在對(duì)象和關(guān)系之間提供了一條橋梁,前臺(tái)的對(duì)象型數(shù)據(jù)和數(shù)據(jù)庫(kù)中的關(guān)系型的數(shù)據(jù)通過(guò)這個(gè)橋梁來(lái)相互轉(zhuǎn)化。

簡(jiǎn)單的講,就是JavaBean和我們的數(shù)據(jù)庫(kù)進(jìn)行一個(gè)關(guān)系映射,一個(gè)實(shí)例對(duì)象對(duì)應(yīng)數(shù)據(jù)庫(kù)的一條記錄,每個(gè)對(duì)象的屬性則對(duì)應(yīng)著數(shù)據(jù)庫(kù)表的字段。

三、添加依賴

// In your root build.gradle file:
buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}
 
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
 
dependencies {
    compile 'org.greenrobot:greendao:3.2.2' // add library
}

四、解鎖技能

  1. GreenDao 3.0采用注解的方式來(lái)定義實(shí)體類,通過(guò)gradle插件生成相應(yīng)的代碼。您可以使用greenDAO Gradle插件,無(wú)需任何其他配置,但至少要設(shè)置schema的版本等;

     // In the build.gradle file of your app project:
     android {
     ...
     }
      
     greendao {
         schemaVersion 1
         daoPackage 'com.ping.greendao.gen'
         targetGenDir 'src/main/java'
     }
    

此外,greendao配置元素支持多種配置選項(xiàng):
- schemaVersion:指定數(shù)據(jù)庫(kù)schema版本號(hào),遷移等操作會(huì)用到;
- daoPackage:通過(guò)gradle插件生成的數(shù)據(jù)庫(kù)相關(guān)文件的包名,默認(rèn)為你的entity所在的包名;
- targetGenDir:自定義生成數(shù)據(jù)庫(kù)文件的目錄,可以將生成的文件放到我們的java目錄中,而不是build中,這樣就不用額外的設(shè)置資源目錄了。

  1. 通過(guò)GreenDao3注解的語(yǔ)法來(lái)定義我們的一個(gè)數(shù)據(jù)庫(kù)實(shí)體類及其數(shù)據(jù)庫(kù)操作方法;
    • 我們先生成一個(gè)實(shí)體類——Meizi,包含id、來(lái)源、和圖片url地址;

        public class Meizi {
        
            private String _id;
            private String source;
            private String url;
        }
      
    • 通過(guò)添加注解為我們的Meizi實(shí)體類生成對(duì)應(yīng)的數(shù)據(jù)庫(kù)操作方法;

        @Entity
        public class Meizi {
        
            @Id(autoincrement = true)
            private Long _id;
            private String source;
            @NotNull
            private String url;
        }
      

這里的幾個(gè)注解含義:
- @Entity:將我們的java普通類變?yōu)橐粋€(gè)能夠被greenDAO識(shí)別的數(shù)據(jù)庫(kù)類型的實(shí)體類;
- @nameInDb:在數(shù)據(jù)庫(kù)中的名字,如不寫則為實(shí)體中類名;
- @Id:選擇一個(gè)long / Long屬性作為實(shí)體ID。 在數(shù)據(jù)庫(kù)方面,它是主鍵。 參數(shù)autoincrement是設(shè)置ID值自增;
- @NotNull:使該屬性在數(shù)據(jù)庫(kù)端成為“NOT NULL”列。 通常使用@NotNull標(biāo)記原始類型(long,int,short,byte)是有意義的;
- @Transient:表明這個(gè)字段不會(huì)被寫入數(shù)據(jù)庫(kù),只是作為一個(gè)普通的java類字段,用來(lái)臨時(shí)存儲(chǔ)數(shù)據(jù)的,不會(huì)被持久化。

- 通過(guò)點(diǎn)擊AndroidStudio中的MakeProject,便發(fā)現(xiàn)GreenDao為我們的Meizi實(shí)體類生成了對(duì)應(yīng)的Getter、Setter方法以及倆個(gè)構(gòu)造函數(shù),同時(shí)在我們配置的com.ping.greendao.gen包下生成了三個(gè)對(duì)應(yīng)類文件DaoMaster、DaoSession和MeiziDao,之后所有相關(guān)的數(shù)據(jù)庫(kù)操作都依靠這三個(gè)文件了;

        @Entity
        public class Meizi {
        
            @Id(autoincrement = true)
            private Long _id;
            private String source;
            @NotNull
            private String url;
            @Generated(hash = 717937950)
            public Meizi(Long _id, String source, @NotNull String url) {
                this._id = _id;
                this.source = source;
                this.url = url;
            }
            @Generated(hash = 507723578)
            public Meizi() {
            }
            public Long get_id() {
                return this._id;
            }
            public void set_id(Long _id) {
                this._id = _id;
            }
            public String getSource() {
                return this.source;
            }
            public void setSource(String source) {
                this.source = source;
            }
            public String getUrl() {
                return this.url;
            }
            public void setUrl(String url) {
                this.url = url;
            }
        }

這里要解釋一下生成的三個(gè)核心類的作用:
<p>

</p>
- DaoMaster:使用greenDAO的切入點(diǎn)。DaoMaster保存數(shù)據(jù)庫(kù)對(duì)象(SQLiteDatabase)并管理特定模式的DAO類(而不是對(duì)象)。 它具有靜態(tài)方法來(lái)創(chuàng)建表或?qū)⑺鼈儎h除。 其內(nèi)部類OpenHelper和DevOpenHelper是在SQLite數(shù)據(jù)庫(kù)中創(chuàng)建模式的SQLiteOpenHelper實(shí)現(xiàn)。一個(gè)DaoMaster就代表著一個(gè)數(shù)據(jù)庫(kù)的連接。
- DaoSession:管理特定模式的所有可用DAO對(duì)象,您可以使用其中一個(gè)getter方法獲取。 DaoSession還為實(shí)體提供了一些通用的持久性方法,如插入,加載,更新,刷新和刪除。 DaoSession可以讓我們使用一些Entity的基本操作和獲取Dao操作類,DaoSession可以創(chuàng)建多個(gè),每一個(gè)都是屬于同一個(gè)數(shù)據(jù)庫(kù)連接的。
- XxxDAO:數(shù)據(jù)訪問(wèn)對(duì)象(DAO)持續(xù)存在并查詢實(shí)體。 對(duì)于每個(gè)實(shí)體,GreenDAO生成一個(gè)DAO。 它比DaoSession有更多的持久化方法,例如:count,loadAll和insertInTx。

  1. 進(jìn)行增刪改操作;
    • 編寫DaoManager,用于創(chuàng)建數(shù)據(jù)庫(kù)、創(chuàng)建數(shù)據(jù)庫(kù)表、包含增刪改查的操作以及數(shù)據(jù)庫(kù)的升級(jí)。

       /**
        * 創(chuàng)建數(shù)據(jù)庫(kù)、創(chuàng)建數(shù)據(jù)庫(kù)表、包含增刪改查的操作以及數(shù)據(jù)庫(kù)的升級(jí)
        * Created by Mr.sorrow on 2017/5/5.
        */
       
       public class DaoManager {
           private static final String TAG = DaoManager.class.getSimpleName();
           private static final String DB_NAME = "greendaotest";
       
           private Context context;
       
           //多線程中要被共享的使用volatile關(guān)鍵字修飾
           private volatile static DaoManager manager = new DaoManager();
           private static DaoMaster sDaoMaster;
           private static DaoMaster.DevOpenHelper sHelper;
           private static DaoSession sDaoSession;
       
           /**
            * 單例模式獲得操作數(shù)據(jù)庫(kù)對(duì)象
            * @return
            */
           public static DaoManager getInstance(){
               return manager;
           }
       
           public void init(Context context){
               this.context = context;
           }
       
           /**
            * 判斷是否有存在數(shù)據(jù)庫(kù),如果沒有則創(chuàng)建
            * @return
            */
           public DaoMaster getDaoMaster(){
               if(sDaoMaster == null) {
                   DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
                   sDaoMaster = new DaoMaster(helper.getWritableDatabase());
               }
               return sDaoMaster;
           }
       
           /**
            * 完成對(duì)數(shù)據(jù)庫(kù)的添加、刪除、修改、查詢操作,僅僅是一個(gè)接口
            * @return
            */
           public DaoSession getDaoSession(){
               if(sDaoSession == null){
                   if(sDaoMaster == null){
                       sDaoMaster = getDaoMaster();
                   }
                   sDaoSession = sDaoMaster.newSession();
               }
               return sDaoSession;
           }
       
           /**
            * 打開輸出日志,默認(rèn)關(guān)閉
            */
           public void setDebug(){
               QueryBuilder.LOG_SQL = true;
               QueryBuilder.LOG_VALUES = true;
           }
       
           /**
            * 關(guān)閉所有的操作,數(shù)據(jù)庫(kù)開啟后,使用完畢要關(guān)閉
            */
           public void closeConnection(){
               closeHelper();
               closeDaoSession();
           }
       
           public void closeHelper(){
               if(sHelper != null){
                   sHelper.close();
                   sHelper = null;
               }
           }
       
           public void closeDaoSession(){
               if(sDaoSession != null){
                   sDaoSession.clear();
                   sDaoSession = null;
               }
           }
       }
      
    • 編寫XxxDaoUtil,用于完成對(duì)某一張數(shù)據(jù)表的具體操作——ORM操作。以創(chuàng)建MeiziDaoUtil為例:

       public class MeiziDaoUtils {
           private static final String TAG = MeiziDaoUtils.class.getSimpleName();
           private DaoManager mManager;
       
           public MeiziDaoUtils(Context context){
               mManager = DaoManager.getInstance();
               mManager.init(context);
           }
       
           /**
            * 完成meizi記錄的插入,如果表未創(chuàng)建,先創(chuàng)建Meizi表
            * @param meizi
            * @return
            */
           public boolean insertMeizi(Meizi meizi){
               boolean flag = false;
               flag = mManager.getDaoSession().getMeiziDao().insert(meizi) == -1 ? false : true;
               Log.i(TAG, "insert Meizi :" + flag + "-->" + meizi.toString());
               return flag;
           }
      
           /**
            * 插入多條數(shù)據(jù),在子線程操作
            * @param meiziList
            * @return
            */
           public boolean insertMultMeizi(final List<Meizi> meiziList) {
               boolean flag = false;
               try {
                   mManager.getDaoSession().runInTx(new Runnable() {
                       @Override
                       public void run() {
                           for (Meizi meizi : meiziList) {
                               mManager.getDaoSession().insertOrReplace(meizi);
                           }
                       }
                   });
                   flag = true;
               } catch (Exception e) {
                   e.printStackTrace();
               }
               return flag;
           }
      
           /**
            * 修改一條數(shù)據(jù)
            * @param meizi
            * @return
            */
           public boolean updateMeizi(Meizi meizi){
               boolean flag = false;
               try {
                   mManager.getDaoSession().update(meizi);
                   flag = true;
               }catch (Exception e){
                   e.printStackTrace();
               }
               return flag;
           }
      
           /**
            * 刪除單條記錄
            * @param meizi
            * @return
            */
           public boolean deleteMeizi(Meizi meizi){
               boolean flag = false;
               try {
                   //按照id刪除
                   mManager.getDaoSession().delete(meizi);
                   flag = true;
               }catch (Exception e){
                   e.printStackTrace();
               }
               return flag;
           }
       
           /**
            * 刪除所有記錄
            * @return
            */
           public boolean deleteAll(){
               boolean flag = false;
               try {
                   //按照id刪除
                   mManager.getDaoSession().deleteAll(Meizi.class);
                   flag = true;
               }catch (Exception e){
                   e.printStackTrace();
               }
               return flag;
           }
      
           /**
            * 查詢所有記錄
            * @return
            */
           public List<Meizi> queryAllMeizi(){
               return mManager.getDaoSession().loadAll(Meizi.class);
           }
       
           /**
            * 根據(jù)主鍵id查詢記錄
            * @param key
            * @return
            */
           public Meizi queryMeiziById(long key){
               return mManager.getDaoSession().load(Meizi.class, key);
           }
      
           /**
            * 使用native sql進(jìn)行查詢操作
            */
           public List<Meizi> queryMeiziByNativeSql(String sql, String[] conditions){
               return mManager.getDaoSession().queryRaw(Meizi.class, sql, conditions);
           }
      
           /**
            * 使用queryBuilder進(jìn)行查詢
            * @return
            */
           public List<Meizi> queryMeiziByQueryBuilder(long id){
               QueryBuilder<Meizi> queryBuilder = mManager.getDaoSession().queryBuilder(Meizi.class);
               return queryBuilder.where(MeiziDao.Properties._id.eq(id)).list();
           }
       }
      
    • 單個(gè)插入操作:

       case R.id.insert:
          mMeiziDaoUtils.insertMeizi(new Meizi(null, "Google",
                   "http://7xi8d6.48096_n.jpg"));
           break;
      
    • 批量插入操作:

       List<Meizi> meiziList = new ArrayList<>();
        meiziList.add(new Meizi(null, "HuaWei",
                "http://7xi8d648096_n.jpg"));
        meiziList.add(new Meizi(null, "Apple",
                "http://7xi8d648096_n.jpg"));
        meiziList.add(new Meizi(null, "MIUI",
                "http://7xi8d648096_n.jpg"));
        mMeiziDaoUtils.insertMultMeizi(meiziList);
      
    • 單個(gè)更改操作:(其中原有的數(shù)據(jù)都不會(huì)保存,如果新建的對(duì)象有屬性沒有設(shè)置,則會(huì)為空,不為空的字段沒有設(shè)置,則報(bào)錯(cuò))

       Meizi meizi = new Meizi();
       meizi.set_id(1002l);
       meizi.setUrl("http://baidu.jpg");
       mMeiziDaoUtils.updateMeizi(meizi);
      
    • 刪除某條記錄操作:

       Meizi meizi1 = new Meizi();
       meizi1.set_id(1002l);
       mMeiziDaoUtils.deleteMeizi(meizi1);
      
    • 刪除所有記錄操作:

      mMeiziDaoUtils.deleteAll();
      
  2. 專為查詢單獨(dú)列出
    • 查詢所有記錄:

       case R.id.checksingle:
           Log.i(TAG, mMeiziDaoUtils.queryMeiziById(1008l).toString());
           break;
      
    • 根據(jù)主鍵查詢記錄:

       case R.id.checkmult:
           List<Meizi> meiziList1 = mMeiziDaoUtils.queryAllMeizi();
           for (Meizi meizi2 : meiziList1) {
               Log.i(TAG, meizi2.toString());
           }
           break;
      
    • 各種條件查詢

      • 使用native sql進(jìn)行條件查詢:

         case R.id.queryNativeSql:
             String sql = "where _id > ?";
             String[] condition = new String[]{"1008"};
             List<Meizi> meiziList2 = mMeiziDaoUtils.queryMeiziByNativeSql(sql, condition);
             for (Meizi meizi2 : meiziList2) {
                 Log.i(TAG, meizi2.toString());
             }
             break;
        
      • 使用queryBuilder進(jìn)行條件查詢:
        ???QueryBuilder能夠讓你在不涉及SQL語(yǔ)句的情況下查詢實(shí)體。寫SQL有幾個(gè)缺點(diǎn),首先是易錯(cuò)的,其次是要在運(yùn)行時(shí)才知道有沒有問(wèn)題(假如屬性名是pid,你寫成了id,也要到運(yùn)營(yíng)時(shí)才會(huì)崩潰),QueryBuilder能夠在編譯時(shí)檢查錯(cuò)誤(如屬性的引用是否錯(cuò)誤)。
        ???關(guān)于Api:在org.greenrobot.greendao.query包下,QueryBuilder類中查看其方法;構(gòu)造函數(shù)可以傳遞我們的Xxx實(shí)體類型,查詢方法有很多邏輯的where方法。where方法中需要設(shè)置WhereCondition類型的條件參數(shù),而在org.greenrobot.greendao包下的Property類中,每一種操作符的方法都返回WhereCondition類型。獲取Property實(shí)例則不需要我們?nèi)プ觯谖覀兊腦xxDao中已經(jīng)有對(duì)應(yīng)的提供,例如我們這里的MeiziDao.Properties.XXX。

         List<Meizi> meiziList2 = mMeiziDaoUtils.queryMeiziByQueryBuilder(1008);
         for (Meizi meizi2 : meiziList2) {
             Log.i(TAG, meizi2.toString());
         }
        

???LazyList懶加載是指一次性查完數(shù)據(jù)保存在內(nèi)存中,然后關(guān)閉所有連接,再次查詢時(shí)從內(nèi)存中獲取。一般查詢大數(shù)據(jù)量時(shí)用。

五、Demo下載

???????源碼鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,932評(píng)論 18 139
  • 一、關(guān)于greenDAO greenDAO應(yīng)該算是當(dāng)前最火的數(shù)據(jù)庫(kù)開源框架了,它是一個(gè)將對(duì)象映射到SQLite數(shù)據(jù)...
    當(dāng)幸福來(lái)敲門58閱讀 13,905評(píng)論 3 19
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,765評(píng)論 18 399
  • 類的屬性和實(shí)例變量是兩個(gè)概念 類的屬性聲明通過(guò)關(guān)鍵字@property聲明, 編譯器在編譯階段將自動(dòng):1.為屬性創(chuàng)...
    羚君閱讀 527評(píng)論 0 0
  • 雪地飛狐 2016-8-19 10:39 一 老師被學(xué)生直呼其名 這種情況,我本人到目前為止還沒有遇到過(guò)。但見過(guò)不...
    雪地飛狐閱讀 427評(píng)論 2 5