弄明白greenDao之前我們應該先了解什麼是ORM(Object Relation Mapping 即 對象關係映射),說白了就是將面向對象編程語言裏的對象與數據庫關聯起來的一種技術,而greenDao就是實現這種技術之一,所以說greenDao其實就是一種將java object 與SQLite Database關聯起來的橋樑,它們之間的關係 如下圖所示;
greenDao ,SQLite Database與Java Object對象之間的關係
2. 爲什麼要使用greenDao
greenDao可以說是當今最流行,最高效而且還在迭代的關係型數據庫。而且greenDao3.0還支持RxJava操作,greenDao如此受歡迎離不開以下幾點:
存取速度快
每秒中可以操作數千個實體 下圖是幾種常見關係型數據庫性能比較;
幾種常用數據庫比較
支持數據庫加密
支持android原生的數據庫SQLite,也支持SQLCipher(在SQLite基礎上加密型數據庫)。
輕量級
greenDao的代碼庫僅僅100k大小
激活實體
處於激活狀態下的實體可以有更多操作方法
支持緩存
能夠將使用的過的實體存在緩存中,下次使用時可以直接從緩存中取,這樣可以使性能提高N個數量級
代碼自動生成
greenDao 會根據modle類自動生成實體類(entities)和Dao對象,並且Dao對象是根據entities類量身定做的並且一 一對應。
3. 怎樣使用greenDao
3.1 入門
3.1.1 配置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的核心類該怎樣使用吧。
3.1.2 核心類介紹
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對象的屬性一一對應。
3.1.3 構建Model類
Molde類需要用java類來定義並且可以通過GreenDao中的註釋來表明Model中的每個屬性在數據庫的中該如何定義;定義model類後點擊Make project選項GreenDao就會自動生成DaoMaster,DaoSession,和DAOS類,生成的代碼將會保存在預先在budle gradle中設置的位置
實體和註釋
GreenDao 通過註釋來定義表單與實體
@Entitypublic 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
基本註釋屬性
@ID 一般會選擇long/Long屬性作爲Entity ID(即數據庫中的主鍵)autoincrement=true表示主鍵會自增如果false就會使用舊值
@Property 可以自定義一個該屬性在數據庫中的名稱,默認情況下數據庫中該屬性名稱是Bean對象中的 屬性名但是不是以駝峯式而是以大寫與下劃線組合形式來命名的比如:customName將命名爲 CUSTOM_NAME;注意:外鍵不能使用該屬性;
@NotNull 確保屬性值不會爲null值;
@Transient 使用該註釋的屬性不會被存入數據庫中;
@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,oruse @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會使用合理的默認值去設置實體類,因此開發者不需要爲每個屬性都添加註釋
@Entitypublic class User { @Id(autoincrement = true) private Long id; @Property(nameInDb = "USERNAME") private String name; @NotNull private int repos; @Transient private int tempUsageCount; ...}
主鍵限制
每個實體類都應該有一個long或者LONG型屬性作爲主鍵;如果你不想用long或者LONG型作爲主鍵,你可以使用一個唯一索引(使用@Index(unique = true)註釋使普通屬性改變成唯一索引屬性)屬性作爲關鍵屬性。
@Idprivate Long id; @Index(unique = true)private String key;
索引屬性
使用@Index 可以將一個屬性變爲數據庫索引;其有倆個參數
name :不使用默認名稱,自定義索引名稱
unique : 給索引增加一個唯一約束,迫使該值唯一
@Entitypublic class User { @Id private Long id; @Index(unique = true) private String name;}
核心代碼初始化
// 下面代碼僅僅需要執行一次,一般會放在applicationhelper = 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();greenDao除了eq()操作之外還有很多其他方法大大方便了我們日常查詢操作比如:
eq():==
noteq():!=
gt(): >
lt():<
ge:>=
le:<=
like():包含
between:倆者之間
in:在某個值內
notIn:不在某個值內
分頁查詢
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");
好了這一期的GreenDao的介紹到這裏就結束了,本期主要講解了greenDao的基本概念與基本操作,下一期我會介紹GreenDao的高級操作:session緩存,多表查詢,多表關聯,自定義參數類型。