Android之greenDao使用(非原創)


文章大綱

一、greenDao簡介
二、greenDao實戰
三、項目源碼下載
四、參考文章

 

一、greenDao簡介

1. 什么是greenDao

  GreenDAO是一個開源的Android ORM(“對象/關系映射”),通過ORM(稱為“對象/關系映射”),在我們數據庫開發過程中節省了開發時間。

 

2. GreenDao的官方文檔

(1)GreenDao:適用於您的SQLite數據庫的Android ORM
(2)GreenDao的github地址
(3)GreenDao的Google討論區
(4)GreenDao 加密SQLCipher for Android官方說明地址
(5) GreenDao使用文檔

3. GreenDao原理

  DAO的core library中有以下幾個核心類,也是后面常用到的,先來大概了解下他們的結構。

 
  • DaoMaster:Dao中的管理者。它保存了sqlitedatebase對象以及操作DAO classes(注意:不是對象)。其提供了一些創建和刪除table的靜態方法,其內部類OpenHelper和DevOpenHelper實現了
    SQLiteOpenHelper,並創建數據庫的框架。

  • DaoSession:會話層。操作具體的DAO對象(注意:是對象),比如各種getter方法。

  • Daos:實際生成的某某DAO類,通常對應具體的java類,比如NoteDao等。其有更多的權限和方法來操作數據庫元素。

  • Entities:持久的實體對象。通常代表了一個數據庫row的標准java properties。

4. GreenDao的優點

(1)一個精簡的庫
(2)性能最大化
(3)內存開銷最小化
(4)易於使用的 APIs
(5)對 Android 進行高度優化

二、greenDao實戰

1. 添加依賴

在項目的build.gradle添加

 

在app的build.gradle添加

 

具體代碼如下:

apply plugin: 'com.android.application' //添加greendao相關的plugin apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion 27 defaultConfig { applicationId "top.daxianwill.greendaodemo" minSdkVersion 15 targetSdkVersion 27 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } greendao{ //指定數據庫schema版本號,遷移等操作會用到; schemaVersion 1 //dao的包名,包名默認是entity所在的包; daoPackage 'com.greendao.gen' //生成數據庫文件的目錄; targetGenDir 'src/main/java' } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.0' //添加greendao相關依賴 implementation 'org.greenrobot:greendao:3.2.2' } 

2. 創建實體類

package top.daxianwill.greendaodemo; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Property; import org.greenrobot.greendao.annotation.Transient; import org.greenrobot.greendao.annotation.Generated; /** * 創建數據庫實體類 * * @Entity 表示這個實體類一會會在數據庫中生成對應的表, @Id 表示該字段是id,注意該字段的數據類型為包裝類型Long @Property 則表示該屬性將作為表的一個字段,其中nameInDb看名字就知道這個屬性在數據庫中對應的數據名稱。 @Transient 該注解表示這個屬性將不會作為數據表中的一個字段。 @NotNull 表示該字段不可以為空 @Unique 表示該字段唯一 */ @Entity public class User { @Id private Long id; @Property(nameInDb = "NAME") private String name; @Transient private int tempUsageCount; // not persisted @Generated(hash = 873297011) public User(Long id, String name) { this.id = id; this.name = name; } @Generated(hash = 586692638) public User() { } public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } } 

注解介紹
(1)@Entity
  用來聲明類實體,表示它將映射為數據表
  @Entity()括號內可加入更詳細的設置,如:
nameInDb =“TABLE_NAME” ——> 聲明該表的表名,默認取類名
createInDb = true ——> 是否創建表,默認為true
generateConstructors = true ——> 是否生成含所有參數的構造函數,默認為true
generateGettersSetters = true ——> 是否生成getter/setter,默認為true

(2)@Id
  用來聲明某變量為表的主鍵,類型使用Long
  @Id()括號可加入autoincrement = true表明自增長

(3)@Unique
  用來聲明某變量的值需為唯一值

(4)@NotNull
  用來聲明某變量的值不能為null

(5)@Property
  @Property(nameInDb = “URL”) 用來聲明某變量在表中的實際字段名為URL

(6)@Transient
  用來聲明某變量不被映射到數據表中

(7)@ToOne、@ToMany
  用來聲明”對一”和“對多”關系,下面舉例說明:
  學生與學校之間一對多的關系(一個學生對應一個學校,一個學校對應有多個學生)

@Entity class Student{ //...省略其他變量 private long fk_schoolId;//外鍵 @ToOne(joinProperty = "fk_schoolId") private School school; } @Entity class School{ //...省略其他變量 @ToMany(referencedJoinProperty = "fk_schoolId") private List<Student> students; } 

學生與課程之間“多對多”的關系(一個學生對應有多門課程,一門課程對應有多個學生)


@Entity class Student{ //...省略其他變量 @ToMany @JoinEntity( entity = StudentWithCourse.class, sourceProperty = "sId", targetProperty = "cId" ) private List<Course> courses; } @Entity class Course{ //...省略其他變量 @ToMany @JoinEntity( entity = StudentWithCourse.class, sourceProperty = "cId", targetProperty = "sId" ) private List<Course> courses; } @Entity class StudentWithCourse{ @Id private Long id; private Long sId; private Long cId; } 

3. Make Project

  利用上面注解寫好表實體后,通過Build—>Make Project重新編譯項目, 將會在表實體中自動生成構造方法和getter/setter方法,另外在指定(或默認)的包中生成DaoMaster、DaoSession以及表實體對應的Dao(如MovieCollectDao)。
  DaoMaster:用於創建數據庫以及獲取DaoSession
  DaoSession:用於獲取各個表對應的Dao類
  各個表對應的Dao:提供了對表進行增刪改查的方法

 

4. 進行數據增刪改查

進行操作前,我們先獲取操作的對象

UserDao mUserDao = MyApplication.getInstances().getDaoSession().getUserDao();

進行數據增加

    public void insert(){ mUser = new User(id++,"any"+id); mUserDao.insert(mUser); notifyListView(); } 

補充:
(1)上述代碼講的是插入單條數據,插入多條數據方式為:

List<MovieCollect> listUserCollect; mUserDao.insertInTx(listUserCollect); 

(2)插入或替換數據
//插入的數據如果已經存在表中,則替換掉舊數據(根據主鍵來檢測是否已經存在)

MovieCollect userCollect;
mUserDao.insertOrReplace(userCollect);//單個數據 List<MovieCollect> listUserCollect; mUserDao.insertOrReplace(listUserCollect);//一組數據 

進行數據刪除

public void delete(){ long l = mUserDao.count() - 1; mUserDao.deleteByKey(l); notifyListView(); } 

補充:
(1)上面代碼講的是刪除一條數據,刪除所有數據方式為:

mUserDao.deleteAll(); 

(2)刪除多條數據

List<User> listUserCollect; mUserDao.deleteInTx(listUserCollect); 

進行數據修改

    public void update(){ mUser = new User((long)3,"any0803"); mUserDao.update(mUser); notifyListView(); } 

補充:
(1)上面代碼介紹的是修改單條數據,修改多條數據方式如下:

List<User> listUserCollect; mUserDao.updateInTx(listUserCollect); 

進行數據查詢

public void loadAll(){ mUserList = mUserDao.loadAll();//查詢所有數據 notifyListView(); } 

補充:
(1)上面代碼介紹的是查詢所有數據,查詢數據數量方式如下:

int count = mUserDao.count(); 

(2)精確(where)條件查詢

//查詢電影名為“肖申克的救贖”的電影 MovieCollect movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Title.eq("肖申克的救贖")).unique(); //查詢電影年份為2017的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.eq(2017)).list(); 

(3)模糊查詢(like)

//查詢電影名含有“傳奇”的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Title.like("傳奇")).list(); //查詢電影名以“我的”開頭的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Title.like("我的%")).list(); 

(4)區間查詢

//大於 //查詢電影年份大於2012年的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.gt(2012)).list(); //大於等於 //查詢電影年份大於等於2012年的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.ge(2012)).list(); //小於 //查詢電影年份小於2012年的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.lt(2012)).list(); //小於等於 //查詢電影年份小於等於2012年的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.le(2012)).list(); //介於中間 //查詢電影年份在2012-2017之間的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.between(2012,2017)).list(); 

(5)升序降序

//查詢電影年份大於2012年的電影,並按年份升序排序 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.gt(2012)).orderAsc(MovieCollectDao.Properties.Year).list(); //查詢電影年份大於2012年的電影,並按年份降序排序 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().where(MovieCollectDao.Properties.Year.gt(2012)).orderDesc(MovieCollectDao.Properties.Year).list(); 

(6)and/or

//and //查詢電影年份大於2012年且電影名以“我的”開頭的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().and(MovieCollectDao.Properties.Year.gt(2012), MovieCollectDao.Properties.Title.like("我的%")).list(); //or //查詢電影年份小於2012年或者大於2015年的電影 List<MovieCollect> movieCollect = mMovieCollectDao.queryBuilder().or(MovieCollectDao.Properties.Year.lt(2012), MovieCollectDao.Properties.Year.gt(2015)).list(); 

5. 緩存處理

  由於GreenDao默認開啟了緩存,所以當你調用A查詢語句取得X實體,然后對X實體進行修改並更新到數據庫,接着再調用A查詢語句取得X實體,會發現X實體的內容依舊是修改前的。其實你的修改已經更新到數據庫中,只是查詢采用了緩存,所以直接返回了第一次查詢的實體。
解決方法:查詢前先清空緩存,清空方法如下

//清空所有數據表的緩存數據 DaoSession daoSession = MyApplication.getInstances().getDaoSession(); daoSession .clear(); //清空某個數據表的緩存數據 UserDao userDao = MyApplication.getInstances().getDaoSession().getUserDao(); userDao.detachAll(); 

6. 數據庫加密

添加依賴

compile 'net.zetetic:android-database-sqlcipher:3.5.7'//使用加密數據庫時需要添加 

獲取操作的數據庫對象

mSQLiteOpenHelper = new MySQLiteOpenHelper(MyApplication.getInstance(), DB_NAME, null);//建庫 mDaoMaster = new DaoMaster(mSQLiteOpenHelper.getEncryptedWritableDb("你的密碼"));//加密 //mDaoMaster = new DaoMaster(mSQLiteOpenHelper.getWritableDatabase()); mDaoSession = mDaoMaster.newSession(); 

溫馨提示:
(1)使用上面步驟得到的DaoSession進行具體的數據表操作。
(2)如果運行后報無法加載有關so庫的異常,請對項目進行clean和rebuild。

7. 數據庫版本升級

  在版本迭代時,我們經常需要對數據庫進行升級,而GreenDAO默認的DaoMaster.DevOpenHelper在進行數據升級時,會把舊表刪除,然后創建新表,並沒有遷移舊數據到新表中,從而造成數據丟失。
  這在實際中是不可取的,因此我們需要作出調整。下面介紹數據庫升級的步驟與要點。
第一步
  新建一個類,繼承DaoMaster.DevOpenHelper,重寫onUpgrade(Database db, int oldVersion, int newVersion)方法,在該方法中使用MigrationHelper進行數據庫升級以及數據遷移。
網上有不少MigrationHelper的源碼,這里采用的是https://github.com/yuweiguocn/GreenDaoUpgradeHelper中的MigrationHelper,它主要是通過創建一個臨時表,將舊表的數據遷移到新表中,大家可以去看下源碼。

public class MyOpenHelper extends DaoMaster.OpenHelper { public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { //把需要管理的數據庫表DAO作為最后一個參數傳入到方法中 MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() { @Override public void onCreateAllTables(Database db, boolean ifNotExists) { DaoMaster.createAllTables(db, ifNotExists); } @Override public void onDropAllTables(Database db, boolean ifExists) { DaoMaster.dropAllTables(db, ifExists); } }, MovieCollectDao.class); } } 

  然后使用MyOpenHelper替代DaoMaster.DevOpenHelper來進行創建數據庫等操作

mSQLiteOpenHelper = new MyOpenHelper(MyApplication.getInstance(), DB_NAME, null);//建庫 mDaoMaster = new DaoMaster(mSQLiteOpenHelper.getWritableDatabase()); mDaoSession = mDaoMaster.newSession(); 

第二步
  在表實體中,調整其中的變量(表字段),一般就是新增/刪除/修改字段。注意:
  (1)新增的字段或修改的字段,其變量類型應使用基礎數據類型的包裝類,如使用Integer而不是int,避免升級過程中報錯。
  (2)根據MigrationHelper中的代碼,升級后,新增的字段和修改的字段,都會默認被賦予null值。

第三步
  將原本自動生成的構造方法以及getter/setter方法刪除,重新Build—>Make Project進行生成。

第四步
  修改Module下build.gradle中數據庫的版本號schemaVersion ,遞增加1即可,最后運行app

    greendao{
    //數據庫版本號,升級時進行修改 schemaVersion 2 //dao的包名,包名默認是entity所在的包; daoPackage 'com.greendao.gen' //生成數據庫文件的目錄; targetGenDir 'src/main/java' } 

8. 代碼混淆

&emsp;&emsp;在proguard-rules.pro文件中添加以下內容進行混淆配置
# greenDAO開始 -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao { public static java.lang.String TABLENAME; } -keep class **$Properties # If you do not use SQLCipher: -dontwarn org.greenrobot.greendao.database.** # If you do not use RxJava: -dontwarn rx.** # greenDAO結束 # 如果按照上面介紹的加入了數據庫加密功能,則需添加一下配置 #sqlcipher數據庫加密開始 -keep class net.sqlcipher.** {*;} -keep class net.sqlcipher.database.** {*;} #sqlcipher數據庫加密結束 

三、項目源碼下載

鏈接:https://pan.baidu.com/s/1uSIvGWPGwIjQp0YTd962AA
密碼:iel2

四、參考文章

    1. https://www.jianshu.com/p/ec37ea99ef69
    2. https://www.jianshu.com/p/53083f782ea2
      3.https://blog.csdn.net/qq_35956194/article/details/79167897


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM