史上最高效的ORM方案——GreenDao3.0詳解
什么是greenDao
弄明白greenDao之前我們應該先了解什么是ORM( Object Relation Mapping 即 對象關系映射),說白了就是將面向對象編程語言里的對象與數據庫關聯起來的一種技術,而greenDao就是實現這種技術之一,所以說greenDao其實就是一種將java object 與SQLite Database關聯起來的橋梁,它們之間的關系 如下圖所示;
greenDao ,SQLite Database與Java Object對象之間的關系
為什么要使用greenDao
-
存取速度快
每秒中可以操作數千個實體 下圖是幾種常見關系型數據庫性能比較;
幾種常用數據庫比較
- 支持數據庫加密
支持android原生的數據庫SQLite,也支持SQLCipher(在SQLite基礎上加密型數據庫)。 - 輕量級
greenDao的代碼庫僅僅100k大小 - 激活實體
處于激活狀態下的實體可以有更多操作方法 - 支持緩存
能夠將使用的過的實體存在緩存中,下次使用時可以直接從緩存中取,這樣可以使性能提高N個數量級 - 代碼自動生成
greenDao 會根據modle類自動生成實體類(entities)和Dao對象,并且Dao對象是根據entities類量身定做的并且一 一對應。
怎樣使用greenDao
入門
- 引入GreenDao
buildscript { repositories { mavenCentral() } dependencies { classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'//greenDao生產代碼插件 } apply plugin: 'org.greenrobot.greendao'//greendao插件 dependencies { compile 'org.greenrobot:greendao:3.2.0'
-
配置數據庫信息
greendao { //數據庫schema版本,也可以理解為數據庫版本號 schemaVersion 2 //設置DaoMaster 、DaoSession、Dao包名 daoPackage 'com.qhn.bhne.footprinting.db' //設置DaoMaster 、DaoSession、Dao目錄 targetGenDir 'src/main/java' //設置生成單元測試目錄 // targetGenDirTest //設置自動生成單元測試用例 // generateTests }
到這里數據庫基本配置已經完成,接下來讓我們一起來了解下greenDao的核心類該怎樣使用吧。
-
核心類介紹
greenDao核心類構成
- DaoMaster:
- 是GreenDao的入口也是greenDao頂級對象,對于一個指定的表單持有數據庫對象(SQLite數據庫)并且能夠管理DAO類- 能夠創建表和刪除表
- 其內部類OpenHelper 與DevOpenHelper是創建SQlite數據庫的SQLiteOpenHelper的具體實現
- DaoSession:
- 對于一個指定的表單可以管理所有的Dao 對象。
- 也能夠對實體類執行 insert ,load,update,refresh.delete操作。
- DaoSession也能跟蹤 identity scope:即session查詢后的實體會存在緩存中,并給該實體生成一個flag來追蹤該實體,下次再次查詢時會直接從緩存中取出來而不是從數據庫中取出來
-
DAOS
- 能夠持久訪問和查詢實體類
- 比起DaoSession有更多的持久化方法 count, loadAll,insertInt等等;
-
Entities- 自動生成的代碼,一般情況下與javaBean對象的屬性一一對應。
-
構建Model類
Molde類需要用java類來定義并且可以通過GreenDao中的注釋來表明Model中的每個屬性在數據庫的中該如何定義; 定義model類后點擊Make project選項GreenDao就會自動生成DaoMaster,DaoSession,和DAOS類,生成的代碼將會保存在預先在budle gradle中設置的位置-
實體和注釋GreenDao
通過注釋來定義表單與實體
@Entity public class User { @Id private Long id; private String name; @Transient private int tempUsageCount; // 沒有存入數據庫中 }
@Entity
- 告訴GreenDao 該Bean類需要持久化。只有使用 @Entity 注釋的Bean類才能被dao類操作;
- @Entity 可以在不使用參數下使用,但是也可以給Entity配置參數
//如果該實體屬于多個表單,可以使用該參數; schema = "myschema", // 該實體屬于激活狀態,激活狀態的實體有更新,刪除,刷新方法; active = true, // 給這個表指定一個名字,默認情況下是名字是類名 nameInDb = "AWESOME_USERS", // 可以給多個屬性定義索引和其他屬性. indexes = { @Index(value = "name DESC", unique = true) }, //是否使用GreenDao創建該表. createInDb = false, // 是否所有的屬性構造器都應該被生成,無參構造器總是被要求 generateConstructors = true, // 如果該類中沒有set get方法是否自動生成 generateGettersSetters = true
-
-
基本注釋屬性
@Entity public class User { @Id(autoincrement = true) private Long id; @Property(nameInDb = "USERNAME") private String name; @NotNull private int repos; @Transient private int tempUsageCount; ...}
@ID一般會選擇long/Long屬性作為Entity ID(即數據庫中的主鍵)autoincrement=true表示主鍵會自增如果false就會使用舊值
@Property可以自定義一個該屬性在數據庫中的名稱,默認情況下數據庫中該屬性名稱是Bean對象中的 屬性名但是不是以駝峰式而是以大寫與下劃線組合形式來命名的比如:customName將命名為 CUSTOM_NAME;注意:外鍵不能使用該屬性;
@NotNull確保屬性值不會為null值;
@Transient使用該注釋的屬性不會被存入數據庫中;
-
主鍵限制每個實體類都應該有一個long或者LONG型屬性作為主鍵;如果你不想用long或者LONG型作為主鍵,你可以使用一個唯一索引(使用@Index(unique = true)注釋使普通屬性改變成唯一索引屬性)屬性作為關鍵屬性。
@Id private Long id; @Index(unique = true) private String key;
-
索引屬性使用 @Index 可以將一個屬性變為數據庫索引;其有倆個參數
- name :不使用默認名稱,自定義索引名稱
-
unique: 給索引增加一個唯一約束,迫使該值唯一
@Entity public class User { @Id private Long id; @Index(unique = true) private String name; }
@Unique
將屬性變成唯一約束屬性;也就是說在數據庫中該值必須唯一
@Generated
提示開發者該屬性不能被修改;并且實體類的方法,屬性,構造器一旦被@Generated注釋就不能被再次修改,否則或報錯
Error:Execution failed for task ':app:greendao'.> Constructor (see ExampleEntity:21) has been changed after generation.Please either mark it with @Keep annotation instead of @Generated to keep it untouched,or use @Generated (without hash) to allow to replace it.
這是因為在通過javabean對象自動生成entities類時,greenDao會增加實體類代碼,@Generated注釋部分與GreenDao增加的代碼相關,胡亂修改@Generated代碼,就會導致entities部分屬性與javabean不匹配導致報錯;有倆種方法可以避免這種錯誤
-
還原 @Generated 改動的部分,當然你也可以完全刪除@Generated 注釋的部分下一次 app build時將會自動生成;
-
使用 @Keep 代替 @Generated 這將告訴greenDao 不會使用該屬性注釋的代碼,但是這種改變可能會破壞entities類和greenDAO的其他部分的連接;注意:默認情況下 greenDao會使用合理的默認值去設置實體類,因此開發者不需要為每個屬性都添加注釋
-
-
核心代碼初始化
// 下面代碼僅僅需要執行一次,一般會放在application helper = new DaoMaster.DevOpenHelper(this, "notes-db", null); db = helper.getWritableDatabase();daoMaster = new DaoMaster(db);daoSession = daoMaster.newSession(); // 在activity或者fragment中獲取Dao對象 noteDao = daoSession.getNoteDao()
完成以上所有工作以后,我們的數據庫就已經自動生成了,接下來就可以對數據庫進行操作了;
-
增刪改查
greenDao的增,刪 ,改操作比較簡單分別調用insert(),delete(),update()方法即可,save()方法比較特殊既能進行插入操作也能執行修改操作這個具體的可以查看 greenDaoAPI
-
Query
與原生SQLitedatabases的查詢操作相比,greenDao Query簡直不能再簡單;greenDao 使用QueryBuilder構建查詢語句也支持原生的SQL查詢語句
- 簡單的查詢語句 在用戶表中查詢叫姓“Joe”的所有的用戶:
List joes = userDao.queryBuilder() .where(Properties.FirstName.eq("Joe")) .orderAsc(Properties.LastName) .list();
- 嵌套挑去查詢語句:查詢一個出生在1970年10月或者以后的"joe"用戶
QueryBuilder qb = userDao.queryBuilder(); qb.where(Properties.FirstName.eq("Joe"),//第一個約束條件姓喬 qb.or(Properties.YearOfBirth.gt(1970),//或者出生日期大于1970年 qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))//并且在1970年出生 但是月份大于 10月的)); List youngJoes = qb.list();
- eq():==
- noteq():!=
- gt(): >
- lt():<
- ge:>=
- le:<=
- like():包含
- between:倆者之間
- in:在某個值內
- notIn:不在某個值內
- 簡單的查詢語句 在用戶表中查詢叫姓“Joe”的所有的用戶:
-
分頁查詢
- limit(int): 限制查詢的數量;
- offset(int): 每次返回的數量; offset不能單獨使用;
-
查詢與LazyList類
-
Query : Query類表示一個查詢能夠執行很多次;而當通過QueryBuilder的任何查詢方法(eg:list())來獲取查詢結果時,querybuilder都會 在其內部創建Query來執行查詢語句的;如果執行多次查詢應該使用Query對象; 如果只想獲取一個結果時可以使用Query(or QueryBuilder)中的unique()方法;
-
LazyList : 可以通過以下方法獲取查詢結果集合;
-
list() 緩存查詢結果;list()類型一般為ArrayList
-
listLazy() 懶查詢,只有當調用list()中的實體對象時才會執行查詢操作并且只緩存第一次被查詢的結果,需要關閉
-
listlazyUncached() 懶查詢,只有當調用list()中的實體對象時才會執行查詢操作并且不緩存;
-
listIterator() 對查詢結果進行遍歷,不緩存,需要關閉;后面三個類是LazyList中的方法,LazyList為了執行不同的緩存策略其內部持有數據庫的cursor對象;一般情況下這三個方法執行完畢后會自動關閉cursor;但是防止在還沒有執行完查詢結果時,對象被終結cursor還是無法被關閉的情況發生,需要手動關閉close();
-
-
多次執行查詢語句
Query對象一旦生成就能多次被使用,你也可以為下一次查詢增加查詢條件
// fetch users with Joe as a first name born in 1970Query query = userDao.queryBuilder().where( Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)).build();List joesOf1970 = query.list(); // using the same Query object, we can change the parameters// to search for Marias born in 1977 later:query.setParameter(0, "Maria");query.setParameter(1, 1977);List mariasOf1977 = query.list();
-
在多線程執行查詢
如果有多條線程執行查詢語句時需要調用forCurrentThread()方法將query對象與當前線程進行綁定,如果其他線程修改該Query對象,greenDao將會拋出一個異常;forCurrentThread()方法通過將Query創建時的時間作為 query標識; -
使用SQL查詢
如果QueryBuilder不能滿足需求可以使用以下倆種方法來實現你的需求;- 首選方法用SQL語句:
Query query = userDao.queryBuilder().where( new StringCondition("_ID IN " + "(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)")).build();
- 備選方法
使用queryRaw 或者queryRawCreate:Query query = userDao.queryRawCreate( ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
- 首選方法用SQL語句:
-
好了這一期的GreenDao的介紹到這里就結束了,本期主要講解了greenDao的基本概念與基本操作,下一期我會介紹GreenDao的高級操作: session緩存,多表查詢,多表關聯,自定義參數類型 。如果你覺得本篇本章有什么不足的地方歡迎在評論區留言;
最后原創不易,喜歡的點個喜歡或者關注一下吧!!
來自:http://www.jianshu.com/p/5449656d56d2