CSDN同步更新:http://blog.csdn.net/bskfnvjtlyzmv867/article/details/71250101
一、簡(jiǎn)介
GreenDAO是一個(gè)開源的安卓ORM框架,能夠使SQLite數(shù)據(jù)庫(kù)的開發(fā)再次變得有趣。它減輕開發(fā)人員處理低級(jí)數(shù)據(jù)庫(kù)需求,同時(shí)節(jié)省開發(fā)時(shí)間。 SQLite是一個(gè)令人敬畏的內(nèi)嵌的關(guān)系數(shù)據(jù)庫(kù),編寫SQL和解析查詢結(jié)果是相當(dāng)乏味和耗時(shí)的任務(wù)。通過(guò)將Java對(duì)象映射到數(shù)據(jù)庫(kù)表(稱為ORM,“對(duì)象/關(guān)系映射”),GreenDAO可以將它們從這些映射中釋放出來(lái),這樣,您可以使用簡(jiǎn)單的面向?qū)ο蟮腁PI來(lái)存儲(chǔ),更新,刪除和查詢數(shù)據(jù)庫(kù)。
簡(jiǎn)單的講,GreenDAO 是一個(gè)將對(duì)象映射到 SQLite 數(shù)據(jù)庫(kù)中的輕量且快速的 ORM 解決方案。
<p></p>
二、ORM概念
對(duì)象-關(guān)系映射(OBJECT/RELATIONALMAPPING,簡(jiǎn)稱ORM),是隨著面向?qū)ο蟮能浖_發(fā)方法發(fā)展而產(chǎn)生的。用來(lái)把對(duì)象模型表示的對(duì)象映射到基于SQL的關(guān)系模型數(shù)據(jù)庫(kù)結(jié)構(gòu)中去。這樣,我們?cè)诰唧w的操作實(shí)體對(duì)象的時(shí)候,就不需要再去和復(fù)雜的 SQL 語(yǔ)句打交道,只需簡(jiǎn)單的操作實(shí)體對(duì)象的屬性和方法。ORM 技術(shù)是在對(duì)象和關(guān)系之間提供了一條橋梁,前臺(tái)的對(duì)象型數(shù)據(jù)和數(shù)據(jù)庫(kù)中的關(guān)系型的數(shù)據(jù)通過(guò)這個(gè)橋梁來(lái)相互轉(zhuǎn)化。
簡(jiǎn)單的講,就是JavaBean和我們的數(shù)據(jù)庫(kù)進(jìn)行一個(gè)關(guān)系映射,一個(gè)實(shí)例對(duì)象對(duì)應(yīng)數(shù)據(jù)庫(kù)的一條記錄,每個(gè)對(duì)象的屬性則對(duì)應(yīng)著數(shù)據(jù)庫(kù)表的字段。
三、添加依賴
// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
}
四、解鎖技能
-
GreenDao 3.0采用注解的方式來(lái)定義實(shí)體類,通過(guò)gradle插件生成相應(yīng)的代碼。您可以使用greenDAO Gradle插件,無(wú)需任何其他配置,但至少要設(shè)置schema的版本等;
// In the build.gradle file of your app project: android { ... } greendao { schemaVersion 1 daoPackage 'com.ping.greendao.gen' targetGenDir 'src/main/java' }
此外,greendao配置元素支持多種配置選項(xiàng):
- schemaVersion:指定數(shù)據(jù)庫(kù)schema版本號(hào),遷移等操作會(huì)用到;
- daoPackage:通過(guò)gradle插件生成的數(shù)據(jù)庫(kù)相關(guān)文件的包名,默認(rèn)為你的entity所在的包名;
- targetGenDir:自定義生成數(shù)據(jù)庫(kù)文件的目錄,可以將生成的文件放到我們的java目錄中,而不是build中,這樣就不用額外的設(shè)置資源目錄了。
-
通過(guò)GreenDao3注解的語(yǔ)法來(lái)定義我們的一個(gè)數(shù)據(jù)庫(kù)實(shí)體類及其數(shù)據(jù)庫(kù)操作方法;
-
我們先生成一個(gè)實(shí)體類——Meizi,包含id、來(lái)源、和圖片url地址;
public class Meizi { private String _id; private String source; private String url; }
-
通過(guò)添加注解為我們的Meizi實(shí)體類生成對(duì)應(yīng)的數(shù)據(jù)庫(kù)操作方法;
@Entity public class Meizi { @Id(autoincrement = true) private Long _id; private String source; @NotNull private String url; }
-
這里的幾個(gè)注解含義:
- @Entity:將我們的java普通類變?yōu)橐粋€(gè)能夠被greenDAO識(shí)別的數(shù)據(jù)庫(kù)類型的實(shí)體類;
- @nameInDb:在數(shù)據(jù)庫(kù)中的名字,如不寫則為實(shí)體中類名;
- @Id:選擇一個(gè)long / Long屬性作為實(shí)體ID。 在數(shù)據(jù)庫(kù)方面,它是主鍵。 參數(shù)autoincrement是設(shè)置ID值自增;
- @NotNull:使該屬性在數(shù)據(jù)庫(kù)端成為“NOT NULL”列。 通常使用@NotNull標(biāo)記原始類型(long,int,short,byte)是有意義的;
- @Transient:表明這個(gè)字段不會(huì)被寫入數(shù)據(jù)庫(kù),只是作為一個(gè)普通的java類字段,用來(lái)臨時(shí)存儲(chǔ)數(shù)據(jù)的,不會(huì)被持久化。
- 通過(guò)點(diǎn)擊AndroidStudio中的MakeProject,便發(fā)現(xiàn)GreenDao為我們的Meizi實(shí)體類生成了對(duì)應(yīng)的Getter、Setter方法以及倆個(gè)構(gòu)造函數(shù),同時(shí)在我們配置的com.ping.greendao.gen包下生成了三個(gè)對(duì)應(yīng)類文件DaoMaster、DaoSession和MeiziDao,之后所有相關(guān)的數(shù)據(jù)庫(kù)操作都依靠這三個(gè)文件了;
@Entity
public class Meizi {
@Id(autoincrement = true)
private Long _id;
private String source;
@NotNull
private String url;
@Generated(hash = 717937950)
public Meizi(Long _id, String source, @NotNull String url) {
this._id = _id;
this.source = source;
this.url = url;
}
@Generated(hash = 507723578)
public Meizi() {
}
public Long get_id() {
return this._id;
}
public void set_id(Long _id) {
this._id = _id;
}
public String getSource() {
return this.source;
}
public void setSource(String source) {
this.source = source;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
}
這里要解釋一下生成的三個(gè)核心類的作用:
<p>
- DaoMaster:使用greenDAO的切入點(diǎn)。DaoMaster保存數(shù)據(jù)庫(kù)對(duì)象(SQLiteDatabase)并管理特定模式的DAO類(而不是對(duì)象)。 它具有靜態(tài)方法來(lái)創(chuàng)建表或?qū)⑺鼈儎h除。 其內(nèi)部類OpenHelper和DevOpenHelper是在SQLite數(shù)據(jù)庫(kù)中創(chuàng)建模式的SQLiteOpenHelper實(shí)現(xiàn)。一個(gè)DaoMaster就代表著一個(gè)數(shù)據(jù)庫(kù)的連接。
- DaoSession:管理特定模式的所有可用DAO對(duì)象,您可以使用其中一個(gè)getter方法獲取。 DaoSession還為實(shí)體提供了一些通用的持久性方法,如插入,加載,更新,刷新和刪除。 DaoSession可以讓我們使用一些Entity的基本操作和獲取Dao操作類,DaoSession可以創(chuàng)建多個(gè),每一個(gè)都是屬于同一個(gè)數(shù)據(jù)庫(kù)連接的。
- XxxDAO:數(shù)據(jù)訪問(wèn)對(duì)象(DAO)持續(xù)存在并查詢實(shí)體。 對(duì)于每個(gè)實(shí)體,GreenDAO生成一個(gè)DAO。 它比DaoSession有更多的持久化方法,例如:count,loadAll和insertInTx。
-
進(jìn)行增刪改操作;
-
編寫DaoManager,用于創(chuàng)建數(shù)據(jù)庫(kù)、創(chuàng)建數(shù)據(jù)庫(kù)表、包含增刪改查的操作以及數(shù)據(jù)庫(kù)的升級(jí)。
/** * 創(chuàng)建數(shù)據(jù)庫(kù)、創(chuàng)建數(shù)據(jù)庫(kù)表、包含增刪改查的操作以及數(shù)據(jù)庫(kù)的升級(jí) * Created by Mr.sorrow on 2017/5/5. */ public class DaoManager { private static final String TAG = DaoManager.class.getSimpleName(); private static final String DB_NAME = "greendaotest"; private Context context; //多線程中要被共享的使用volatile關(guān)鍵字修飾 private volatile static DaoManager manager = new DaoManager(); private static DaoMaster sDaoMaster; private static DaoMaster.DevOpenHelper sHelper; private static DaoSession sDaoSession; /** * 單例模式獲得操作數(shù)據(jù)庫(kù)對(duì)象 * @return */ public static DaoManager getInstance(){ return manager; } public void init(Context context){ this.context = context; } /** * 判斷是否有存在數(shù)據(jù)庫(kù),如果沒有則創(chuàng)建 * @return */ public DaoMaster getDaoMaster(){ if(sDaoMaster == null) { DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null); sDaoMaster = new DaoMaster(helper.getWritableDatabase()); } return sDaoMaster; } /** * 完成對(duì)數(shù)據(jù)庫(kù)的添加、刪除、修改、查詢操作,僅僅是一個(gè)接口 * @return */ public DaoSession getDaoSession(){ if(sDaoSession == null){ if(sDaoMaster == null){ sDaoMaster = getDaoMaster(); } sDaoSession = sDaoMaster.newSession(); } return sDaoSession; } /** * 打開輸出日志,默認(rèn)關(guān)閉 */ public void setDebug(){ QueryBuilder.LOG_SQL = true; QueryBuilder.LOG_VALUES = true; } /** * 關(guān)閉所有的操作,數(shù)據(jù)庫(kù)開啟后,使用完畢要關(guān)閉 */ public void closeConnection(){ closeHelper(); closeDaoSession(); } public void closeHelper(){ if(sHelper != null){ sHelper.close(); sHelper = null; } } public void closeDaoSession(){ if(sDaoSession != null){ sDaoSession.clear(); sDaoSession = null; } } }
-
編寫XxxDaoUtil,用于完成對(duì)某一張數(shù)據(jù)表的具體操作——ORM操作。以創(chuàng)建MeiziDaoUtil為例:
public class MeiziDaoUtils { private static final String TAG = MeiziDaoUtils.class.getSimpleName(); private DaoManager mManager; public MeiziDaoUtils(Context context){ mManager = DaoManager.getInstance(); mManager.init(context); } /** * 完成meizi記錄的插入,如果表未創(chuàng)建,先創(chuàng)建Meizi表 * @param meizi * @return */ public boolean insertMeizi(Meizi meizi){ boolean flag = false; flag = mManager.getDaoSession().getMeiziDao().insert(meizi) == -1 ? false : true; Log.i(TAG, "insert Meizi :" + flag + "-->" + meizi.toString()); return flag; } /** * 插入多條數(shù)據(jù),在子線程操作 * @param meiziList * @return */ public boolean insertMultMeizi(final List<Meizi> meiziList) { boolean flag = false; try { mManager.getDaoSession().runInTx(new Runnable() { @Override public void run() { for (Meizi meizi : meiziList) { mManager.getDaoSession().insertOrReplace(meizi); } } }); flag = true; } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 修改一條數(shù)據(jù) * @param meizi * @return */ public boolean updateMeizi(Meizi meizi){ boolean flag = false; try { mManager.getDaoSession().update(meizi); flag = true; }catch (Exception e){ e.printStackTrace(); } return flag; } /** * 刪除單條記錄 * @param meizi * @return */ public boolean deleteMeizi(Meizi meizi){ boolean flag = false; try { //按照id刪除 mManager.getDaoSession().delete(meizi); flag = true; }catch (Exception e){ e.printStackTrace(); } return flag; } /** * 刪除所有記錄 * @return */ public boolean deleteAll(){ boolean flag = false; try { //按照id刪除 mManager.getDaoSession().deleteAll(Meizi.class); flag = true; }catch (Exception e){ e.printStackTrace(); } return flag; } /** * 查詢所有記錄 * @return */ public List<Meizi> queryAllMeizi(){ return mManager.getDaoSession().loadAll(Meizi.class); } /** * 根據(jù)主鍵id查詢記錄 * @param key * @return */ public Meizi queryMeiziById(long key){ return mManager.getDaoSession().load(Meizi.class, key); } /** * 使用native sql進(jìn)行查詢操作 */ public List<Meizi> queryMeiziByNativeSql(String sql, String[] conditions){ return mManager.getDaoSession().queryRaw(Meizi.class, sql, conditions); } /** * 使用queryBuilder進(jìn)行查詢 * @return */ public List<Meizi> queryMeiziByQueryBuilder(long id){ QueryBuilder<Meizi> queryBuilder = mManager.getDaoSession().queryBuilder(Meizi.class); return queryBuilder.where(MeiziDao.Properties._id.eq(id)).list(); } }
-
單個(gè)插入操作:
case R.id.insert: mMeiziDaoUtils.insertMeizi(new Meizi(null, "Google", "http://7xi8d6.48096_n.jpg")); break;
-
批量插入操作:
List<Meizi> meiziList = new ArrayList<>(); meiziList.add(new Meizi(null, "HuaWei", "http://7xi8d648096_n.jpg")); meiziList.add(new Meizi(null, "Apple", "http://7xi8d648096_n.jpg")); meiziList.add(new Meizi(null, "MIUI", "http://7xi8d648096_n.jpg")); mMeiziDaoUtils.insertMultMeizi(meiziList);
-
單個(gè)更改操作:(其中原有的數(shù)據(jù)都不會(huì)保存,如果新建的對(duì)象有屬性沒有設(shè)置,則會(huì)為空,不為空的字段沒有設(shè)置,則報(bào)錯(cuò))
Meizi meizi = new Meizi(); meizi.set_id(1002l); meizi.setUrl("http://baidu.jpg"); mMeiziDaoUtils.updateMeizi(meizi);
-
刪除某條記錄操作:
Meizi meizi1 = new Meizi(); meizi1.set_id(1002l); mMeiziDaoUtils.deleteMeizi(meizi1);
-
刪除所有記錄操作:
mMeiziDaoUtils.deleteAll();
-
-
專為查詢單獨(dú)列出;
-
查詢所有記錄:
case R.id.checksingle: Log.i(TAG, mMeiziDaoUtils.queryMeiziById(1008l).toString()); break;
-
根據(jù)主鍵查詢記錄:
case R.id.checkmult: List<Meizi> meiziList1 = mMeiziDaoUtils.queryAllMeizi(); for (Meizi meizi2 : meiziList1) { Log.i(TAG, meizi2.toString()); } break;
-
各種條件查詢:
-
使用native sql進(jìn)行條件查詢:
case R.id.queryNativeSql: String sql = "where _id > ?"; String[] condition = new String[]{"1008"}; List<Meizi> meiziList2 = mMeiziDaoUtils.queryMeiziByNativeSql(sql, condition); for (Meizi meizi2 : meiziList2) { Log.i(TAG, meizi2.toString()); } break;
-
使用queryBuilder進(jìn)行條件查詢:
???QueryBuilder能夠讓你在不涉及SQL語(yǔ)句的情況下查詢實(shí)體。寫SQL有幾個(gè)缺點(diǎn),首先是易錯(cuò)的,其次是要在運(yùn)行時(shí)才知道有沒有問(wèn)題(假如屬性名是pid,你寫成了id,也要到運(yùn)營(yíng)時(shí)才會(huì)崩潰),QueryBuilder能夠在編譯時(shí)檢查錯(cuò)誤(如屬性的引用是否錯(cuò)誤)。
???關(guān)于Api:在org.greenrobot.greendao.query包下,QueryBuilder類中查看其方法;構(gòu)造函數(shù)可以傳遞我們的Xxx實(shí)體類型,查詢方法有很多邏輯的where方法。where方法中需要設(shè)置WhereCondition類型的條件參數(shù),而在org.greenrobot.greendao包下的Property類中,每一種操作符的方法都返回WhereCondition類型。獲取Property實(shí)例則不需要我們?nèi)プ觯谖覀兊腦xxDao中已經(jīng)有對(duì)應(yīng)的提供,例如我們這里的MeiziDao.Properties.XXX。List<Meizi> meiziList2 = mMeiziDaoUtils.queryMeiziByQueryBuilder(1008); for (Meizi meizi2 : meiziList2) { Log.i(TAG, meizi2.toString()); }
-
-
???LazyList懶加載是指一次性查完數(shù)據(jù)保存在內(nèi)存中,然后關(guān)閉所有連接,再次查詢時(shí)從內(nèi)存中獲取。一般查詢大數(shù)據(jù)量時(shí)用。
五、Demo下載
???????源碼鏈接