文章大綱 一、greenDao簡介二、greenDao實戰三、項目源碼下載四、參考文章 一、greenDao簡介 1. 什麼是greenDao GreenDAO是一個開源的Android ORM(“對象/關係映射”),通過ORM(稱為“對象/關係映射”),在我們資料庫開發過程中節省了開發時間。 2. ...
文章大綱
一、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. 代碼混淆
  在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