一、GreenDao 簡介

??GreenDAO 是一款開源的面向 Android 的輕便、快捷的 ORM 框架,將 Java 物件映射到 SQLite 資料庫中,我們操作資料庫的時候,不再需要撰寫復雜的 SQL陳述句, 在性能方面,greenDAO 針對 Android 進行了高度優化,最小的記憶體開銷 、依賴體積小 同時還是支持 資料庫加密,
??greenDAO 官網地址:greenrobot.org/greendao/
??greenDAO GitHub 原始碼地址:greenrobot/greenDAO
二、GreenDao 特征
- 1、支持 protocol buffer(protobuf) 協議
GreenDao 支持 protocol buffer(protobuf) 協議資料的直接存盤,如果你通過 protobuf 協議與服務器互動,將不需要任何的映射 - 2、代碼生成
greenDAO 會根據配置資訊自動生成核心管理類以及 DAO 物件 - 3、性能
所有 ORM 資料庫的,greenDAO 是最快的,greenDAO 不作性能方面任何妥協
三、核心類介紹
1、DaoMaster:
??使用 greenDAO 的入口點,DaoMaster 負責管理資料庫物件(SQLiteDatabase)和 DAO 類(物件),我們可以通過它內部類 OpenHelper 和 DevOpenHelper SQLiteOpenHelper 創建不同模式的 SQLite 資料庫,
2、DaoSession :
??管理指定模式下的所有 DAO 物件,DaoSession 提供了一些通用的持久性方法比如插入、負載、更新和洗掉物體,
3、XxxDAO :
??對于每個物體類, greenDAO 都會生成一個與之對應 DAO 物件,如:User 物體,則會生成一個 UserDao 類
4、Entities:
??可持久化物件,通常,物體物件代表一個資料庫行,使用標準 Java 屬性(如一個 POJO 或 JavaBean )

四、集成 GreenDao
a、設定倉庫與插件(Project: build.gradle)
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
b、配置依賴 ( Module:app build.gradle )
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
// This is only needed if you want to use encrypted databases
compile 'net.zetetic:android-database-sqlcipher:3.5.6' //加密庫依賴(可選項)
}
c、配置資料庫相關資訊 ( Module:app build.gradle )
greendao {
schemaVersion 1 // 資料庫版本號
daoPackage 'com.example.zhangruirui.greendao' // 設定 DaoMaster、DaoSession、Dao 包名
targetGenDir 'src/main/java' // 設定 DaoMaster、DaoSession、Dao 目錄
}
d、基本使用步驟
// 生成資料庫檔案,名為 students-db
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "students-db", null);
SQLiteDatabase db = helper.getWritableDatabase();
// 建立特定模式下的所有的 DAO 物件和資料 db 物件的映射
DaoMaster master = new DaoMaster(db);
// 管理特定模式下的所有 DAO 物件,并提供一些通用的 CRUD 持久化方法
DaoSession session = master.newSession();
// 得到指定的 StudentDao 物件
StudentDao dao = session.getStudentDao();
dao.insert(student);
//...
五、實戰
1、我們寫一個簡單的物體類(User),測驗一下
package com.example.zhangruirui;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class User {
@Id
private long id;
private String name;
private int age;
@Generated(hash = 446251977)
public User(long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Generated(hash = 586692638)
public User() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2、點擊 Make Project(或者 Make Moudle ‘App’) 編譯一下工程 ,如果配置正確,會在配置的包目錄下自動會生成 DaoMaster,DaoSession 和 UserDao 類 ,

3、然后我們定義 OpenHelper 類:UserDBOpenHelper
package com.example.zhangruirui.greendao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.example.zhangruirui.DaoMaster;
public class UserDBOpenHelper extends DaoMaster.DevOpenHelper {
public UserDBOpenHelper(Context context, String name) {
super(context, name);
}
public UserDBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
DaoMaster.dropAllTables(wrap(db), true);
}
}
4、然后,類似 SQLite ,我們需要定義 DBManager:UserManager 創建單例實體,來供外部操作資料庫
package com.example.zhangruirui.greendao;
import android.content.Context;
import android.support.annotation.WorkerThread;
import com.google.gson.Gson;
import java.io.Serializable;
import java.lang.reflect.Type;
public class UserManager {
private volatile static UserManager mInstance = null;
private Context mContext;
private UserStorage mUserStorage = new UserStorage(mContext);
private UserManager() {
}
public static UserManager getInstance() {
if (mInstance == null) {
synchronized (UserManager.class) {
if (mInstance == null) {
mInstance = new UserManager();
}
}
}
return mInstance;
}
public <T> T getUserAge(String key, Type typeOfT) {
try {
String json = mUserStorage.getUserAge(key);
Gson gson = new Gson();
CacheEntry entry = gson.fromJson(json, CacheEntry.class);
return gson.fromJson(entry.mJson, typeOfT);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@WorkerThread
public void setUserAge(String key, Object entity, Type type) {
setUserInner(key, entity, type);
}
@WorkerThread
private void setUserInner(String key, Object entity, Type type) {
Gson gson = new Gson();
String json = gson.toJson(entity, type);
CacheEntry entry = new CacheEntry(json);
json = gson.toJson(entry, CacheEntry.class);
if (entity == null) {
mUserStorage.removeUser(key);
} else {
mUserStorage.addUser(key, json);
}
}
static class CacheEntry implements Serializable {
final String mJson;
CacheEntry(String json) {
mJson = json;
}
}
}
5、獲取 UserDao 對資料庫表進行 CRUD 操作即可:UserStorage
package com.example.zhangruirui.greendao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.WorkerThread;
import com.example.zhangruirui.User;
import org.greenrobot.greendao.query.DeleteQuery;
import org.greenrobot.greendao.query.QueryBuilder;
public class UserStorage {
private SQLiteDatabase mDatabase;
private UserDao mUserDao; // 獲取 dao 物件
private final static String DB_NAME = "user_name_age.db"; // 定義資料庫名
// 獲取核心類的實體
UserStorage(Context context) {
DaoMaster.OpenHelper helper = new UserDBOpenHelper(context, DB_NAME, null);
try {
mDatabase = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(mDatabase);
DaoSession daoSession = daoMaster.newSession();
mUserDao = daoSession.getUserDao();
} catch (Exception e) {
e.printStackTrace();
}
}
public User getUserByName(String name) {
if (!isDataBaseValid()) {
return null;
}
return mUserDao.queryBuilder().where(UserDao.Properties.Name.eq(name)).unique();
}
/**
* 根據用戶的名字洗掉對應的記錄
*/
public void removeUser(String name) {
if (!isDataBaseValid()) {
return;
}
try {
QueryBuilder<User> qb = mUserDao.queryBuilder();
DeleteQuery<User> bd = qb.where(UserDao.Properties.Name.eq(name))
.buildDelete();
bd.executeDeleteWithoutDetachingEntities();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 新增記錄,如果存在則更新,不存在直接插入
*/
@WorkerThread
public synchronized void addUser(String name, String json) {
if (!isDataBaseValid()) {
return;
}
try {
User user = new User();
user.setName(name);
user.setAge(json);
/**
* 解決 Exception:
* Cannot update entity without key - was it inserted before?
*/
User oldUser = getUserByName(name);
if (oldUser != null) {
user.setId(oldUser.getId());
}
// mUserDao.save(user);
if (getUserByName(name) == null) {
mUserDao.insert(user);
} else {
mUserDao.update(user);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 洗掉所有資料
*/
@WorkerThread
public synchronized void deleteAll() {
mUserDao.deleteAll();
}
private boolean isDataBaseValid() {
return mUserDao != null;
}
public String getUserAge(String key) {
return mUserDao.queryBuilder().where(UserDao.Properties.Name.eq(key)).list().get(0).getAge();
}
}
六、注解
@Entity
表明這個物體類會在資料庫中生成一個與之相對應的表
@Entity(
// If you have more than one schema, you can tell greenDAO
// to which schema an entity belongs (pick any string as a name).
schema = "myschema",
// Flag to make an entity "active": Active entities have update,
// delete, and refresh methods.
active = true,
// Specifies the name of the table in the database.
// By default, the name is based on the entities class name.
nameInDb = "AWESOME_USERS",
// Define indexes spanning multiple columns here.
indexes = {
@Index(value = "name DESC", unique = true)
},
// Flag if the DAO should create the database table (default is true).
// Set this to false, if you have multiple entities mapping to one table,
// or the table creation is done outside of greenDAO.
createInDb = false,
// Whether an all properties constructor should be generated.
// A no-args constructor is always required.
generateConstructors = true,
// Whether getters and setters for properties should be generated if missing.
generateGettersSetters = true
)
public class User {
...
}
@Id(autoincrement = true)
對應資料表中的 Id 欄位,主鍵,必須為 Long 型
如果需要使用主鍵自增,此時 id 型別為 Long(注意是大寫的)
/**
* Marks field is the primary key of the entity's table
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface Id {
/**
* Specifies that id should be auto-incremented (works only for Long/long fields)
* Autoincrement on SQLite introduces additional resources usage and usually can be avoided
* @see <a href="https://www.sqlite.org/autoinc.html">SQLite documentation</a>
*/
boolean autoincrement() default false;
}
@Transient
添加此標記后不會生成資料庫表的列,僅僅作為一個普通的 java 類欄位,用來臨時存盤資料的,不會被持久化
@Unique
表名該屬性在資料庫中只能有唯一值
@Index(unique = true)
七、重要的 api 方法
注意:這些 api 方法中,提到的 key,都是指的主鍵 Long id
1、查詢
http://greenrobot.org/greendao/documentation/queries/
https://juejin.im/post/5abf6ef9f265da2396128456
QueryBuilder.java
2、插入
/**
* Insert an entity into the table associated with a concrete DAO.
*
* @return row ID of newly inserted entity
*/
public long insert(T entity) {
return executeInsert(entity, statements.getInsertStatement(), true);
}
3、更新
public void update(T entity) {
assertSinglePk();
DatabaseStatement stmt = statements.getUpdateStatement();
if (db.isDbLockedByCurrentThread()) {
synchronized (stmt) {
if (isStandardSQLite) {
updateInsideSynchronized(entity, (SQLiteStatement) stmt.getRawStatement(), true);
} else {
updateInsideSynchronized(entity, stmt, true);
}
}
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
synchronized (stmt) {
updateInsideSynchronized(entity, stmt, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}
4、插入or更新
public long insertOrReplace(T entity) {
return executeInsert(entity, statements.getInsertOrReplaceStatement(), true);
}
private long executeInsert(T entity, DatabaseStatement stmt, boolean setKeyAndAttach) {
long rowId;
if (db.isDbLockedByCurrentThread()) {
rowId = insertInsideTx(entity, stmt);
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
rowId = insertInsideTx(entity, stmt);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
if (setKeyAndAttach) {
updateKeyAfterInsertAndAttach(entity, rowId, true);
}
return rowId;
}
save() 方法:
通過 key 屬性判斷是否存在,如果存在就更新資料,如果 key 為 null 就插入,這里的 key 是什么東東?這就是我今天被坑的地方,這個 key 就是 Long id 這個欄位,也就是表中的主鍵!!!
/**
* "Saves" an entity to the database: depending on the existence of the key property, it will be inserted
* (key is null) or updated (key is not null).
* <p>
* This is similar to {@link #insertOrReplace(Object)}, but may be more efficient, because if a key is present,
* it does not have to query if that key already exists.
*/
public void save(T entity) {
if (hasKey(entity)) {
update(entity);
} else {
insert(entity);
}
}
5、洗掉
/** Deletes the given entity from the database. Currently, only single value PK entities are supported. */
public void delete(T entity) {
assertSinglePk();
K key = getKeyVerified(entity);
deleteByKey(key);
}
八、入坑系列
1、https://www.jianshu.com/p/7bb9693ea380
2、https://blog.csdn.net/anyanyan07/article/details/73410053
3、打包混淆問題(打包后的 APK,使用不了): 打包后使用不了,debug 能使用,很明顯,混淆的問題,報錯如下:
https://blog.csdn.net/ddxxii/article/details/54866871
Caused by: org.greenrobot.greendao.DaoException: Could not init DAOConfig
解決辦法:
針對 GreenDao 3.0 ,使用時,發布包需要設定混淆
#greendao
-keep class org.greenrobot.greendao.**{*;}
-keep public interface org.greenrobot.greendao.**
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
#optional
-keep class net.sqlcipher.database.**{*;}
-keep public interface net.sqlcipher.database.**
-dontwarn net.sqlcipher.database.**
-dontwarn org.greenrobot.greendao.**
------致所有正在努力奮斗的程式猿們!加油!!
有碼走遍天下 無碼寸步難行
1024 - 夢想,永不止步!
愛編程 不愛Bug
愛加班 不愛黑眼圈
固執 但不偏執
瘋狂 但不瘋癲
生活里的菜鳥
作業中的大神
身懷寶藏,一心憧憬星辰大海
追求極致,目標始于高山之巔
一群懷揣好奇,夢想改變世界的孩子
一群追日逐浪,正在改變世界的極客
你們用最美的語言,詮釋著科技的力量
你們用極速的創新,引領著時代的變遷
——樂于分享,共同進步,歡迎補充
——Treat Warnings As Errors
——Any comments greatly appreciated
——Talking is cheap, show me the code
——誠心歡迎各位交流討論!QQ:1138517609
——CSDN:https://blog.csdn.net/u011489043
——簡書:https://www.jianshu.com/u/4968682d58d1
——GitHub:https://github.com/selfconzrr
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/243335.html
標籤:其他
