Sqlite作為android重要的數(shù)據(jù)存儲(chǔ)庫,原生類SQLiteOpenHelper使用起來繁瑣容易出錯(cuò),本著"偷懶"的目的,來學(xué)習(xí)一下當(dāng)下十分受歡迎的ORM 框架: greenDAO;網(wǎng)上教程不少,但是大都是針對3.0之前的版本,greenDAO2和3的構(gòu)建和生成代碼的方式區(qū)別很大,最終還是通過greenDAO github上的介紹,慢慢摸索,成功的在項(xiàng)目中構(gòu)建了greenDAO,本文章寫于greenDao更新至3.2版本
一、什么是greenDAO?
官方介紹:
greenDAO github
greenDAO 官網(wǎng)
網(wǎng)友的博客:
Android ORM框架 GreenDao3.0的使用
greenDAO3開始使用注解的方式定義實(shí)體類(entity),并且是通過安裝gradle插件來生成代碼。
二、如何使用greenDAO
構(gòu)建之前,不熟悉gradle概念的同學(xué)建議學(xué)習(xí)Gradle for android 系列教程
先來看下greenDAO 官方構(gòu)建介紹:
開始搭建:
- github中提示添加maven倉庫,但是android studio 項(xiàng)目已經(jīng)默認(rèn)包含了jcenter倉庫,而jcenter倉庫就是maven倉庫的一個(gè)分支,因此我們不要再添加倉庫,直接添加classPath即可
- 在moudle下的build.gradle文件中 申明插件以及配置greendao(可以不配置)
- 并在dependencies中添加compile
/* green dao */
compile 'org.greenrobot:greendao:3.2.0
三、使用greenDAO
- 編寫實(shí)體類:User類,使用greendao @Entity注解
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class User {
@Id
private long id;
private String userName;
private int age;
private String gender;
}
- 編譯項(xiàng)目,build后greendao插件會(huì)為所有帶有該注解的實(shí)體生成Dao文件,以及DaoManager與DaoSession,默認(rèn)生成目錄為build/generated/source ,如果我們在gradle腳本中配置了,則會(huì)生成在我們的配置目錄
不配置,則在默認(rèn)目錄(build/generated/source/greendao)下生成dao文件:
四、greenDAO 注解
1.實(shí)體@Entity注解
schema:告知GreenDao當(dāng)前實(shí)體屬于哪個(gè)schema
active:標(biāo)記一個(gè)實(shí)體處于活動(dòng)狀態(tài),活動(dòng)實(shí)體有更新、刪除和刷新方法
nameInDb:在數(shù)據(jù)中使用的別名,默認(rèn)使用的是實(shí)體的類名
indexes:定義索引,可以跨越多個(gè)列
createInDb:標(biāo)記創(chuàng)建數(shù)據(jù)庫表
2.基礎(chǔ)屬性注解
@Id :主鍵 Long型,可以通過@Id(autoincrement = true)設(shè)置自增長
@Property:設(shè)置一個(gè)非默認(rèn)關(guān)系映射所對應(yīng)的列名,默認(rèn)是的使用字段名 舉例:@Property (nameInDb="name")
@NotNul:設(shè)置數(shù)據(jù)庫表當(dāng)前列不能為空
@Transient :添加次標(biāo)記之后不會(huì)生成數(shù)據(jù)庫表的列
3.索引注解
@Index:使用@Index作為一個(gè)屬性來創(chuàng)建一個(gè)索引,通過name設(shè)置索引別名,也可以通過unique給索引添加約束
@Unique:向數(shù)據(jù)庫列添加了一個(gè)唯一的約束
4.關(guān)系注解
@ToOne:定義與另一個(gè)實(shí)體(一個(gè)實(shí)體對象)的關(guān)系
@ToMany:定義與多個(gè)實(shí)體對象的關(guān)系
五、使用greenDAO 進(jìn)行數(shù)據(jù)操作(詳情可查閱博友的文章)
- 使用單例模式構(gòu)建一個(gè)工具類來獲取daoSession等對象
public class GreenDaoHelper {
private static DaoMaster.DevOpenHelper devOpenHelper;
private static SQLiteDatabase database;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
/**
* 初始化greenDao
* 建議放在Application 中進(jìn)行
*/
public static void initDatabase(){
// 通過 DaoMaster 的內(nèi)部類 DevOpenHelper,你可以得到一個(gè)便利的 SQLiteOpenHelper 對象。
// 可能你已經(jīng)注意到了,你并不需要去編寫「CREATE TABLE」這樣的 SQL 語句,因?yàn)?greenDAO 已經(jīng)幫你做了。
// 注意:默認(rèn)的 DaoMaster.DevOpenHelper 會(huì)在數(shù)據(jù)庫升級時(shí),刪除所有的表,意味著這將導(dǎo)致數(shù)據(jù)的丟失。
// 所以,在正式的項(xiàng)目中,你還應(yīng)該做一層封裝,來實(shí)現(xiàn)數(shù)據(jù)庫的安全升級。
devOpenHelper = new DaoMaster.DevOpenHelper(AppContext.getInstance(),"cache-db",null);//數(shù)據(jù)庫名
database = devOpenHelper.getWritableDatabase();
// 注意:該數(shù)據(jù)庫連接屬于 DaoMaster,所以多個(gè) Session 指的是相同的數(shù)據(jù)庫連接。
daoMaster = new DaoMaster(database);
daoSession = daoMaster.newSession();
}
public static DaoSession getDaoSession() {
return daoSession;
}
public static SQLiteDatabase getDb() {
return database;
}
}
數(shù)據(jù)庫的增刪改查我們都將通過Dao來操作
- 增加數(shù)據(jù)(直接inser一個(gè)對象即可,十分簡便)
private UserDao mUserDao = GreenDaoHelper.getDaoSession().getUserDao();
public void insertData(){
//數(shù)據(jù)庫的增刪改查我們都將通過UserDao來進(jìn)行,插入操作如下:
mUserDao.insert(new User(null,"david",23,"male"));//id傳null 即自增。==> 這里是Long類型而不是long
}
小手一抖,一口氣插了6條數(shù)據(jù):
- 刪除數(shù)據(jù)(刪除數(shù)據(jù)和修改數(shù)據(jù)的思路一樣,都是要先查找到數(shù)據(jù)),操作很簡單,效果就不一一截圖了
//查詢id等于3的所有行并刪除
User user = mUserDao.queryBuilder().where(UserDao.Properties.Id.eq(3)).build().unique();
if (user == null) ToastUtils.show(getView(), "用戶不存在!");
else mUserDao.deleteByKey(user.getId());
//查詢id小于5的集合并刪除
List<User> userList = (List<User>) mUserDao.queryBuilder().where(UserDao.Properties.Id.le(5)).build().list();
for (User user : userList) {
mUserDao.delete(user);
}
//刪除所有數(shù)據(jù)
mUserDao.deleteAll();
- 修改數(shù)據(jù)
//修改id為2的行
User user = new User((long) 2, "Nancy", 23, "female");
mUserDao.update(user);
//查詢id>= 3 且like ("%david%")
User user = mUserDao.queryBuilder()
.where(UserDao.Properties.Id.ge(3), UserDao.Properties.UserName.like("%david%")).build().unique();
if (user == null) {
ToastUtils.show(getView(), "用戶不存在!");
} else {
user.setUserName("王五");
mUserDao.update(user);
}
- 查詢數(shù)據(jù)
//查出所有數(shù)據(jù)
List<User> users = mUserDao.loadAll();
//查詢id為1~4之間的數(shù),查出前2個(gè)
List<User> users = mUserDao.queryBuilder()
.where(UserDao.Properties.Id.between(1, 4)).limit(2).build().list();
六、數(shù)據(jù)庫升級
數(shù)據(jù)庫升級的意義:
如果我們再項(xiàng)目中使用了數(shù)據(jù)庫。而數(shù)據(jù)庫的結(jié)構(gòu)在第一版的時(shí)候定下來,之后發(fā)布功能更新,或增加業(yè)務(wù)邏輯,原來的數(shù)據(jù)庫結(jié)構(gòu)可能就不適用了。而如果數(shù)據(jù)庫的結(jié)構(gòu)與之前版本的結(jié)構(gòu)不同,新版本的應(yīng)用讀取舊數(shù)據(jù)庫肯定會(huì)出問題。解決辦法只有兩種:
1.讓用戶卸載老版本再安裝新的程序;
2.軟件自行更新數(shù)據(jù)庫結(jié)構(gòu)。
第一種辦法很明顯不具備可操作性,而且用戶一旦卸載軟件,數(shù)據(jù)就丟失了,這是不能容忍的事情。因此,作為開發(fā)者必須妥善處理數(shù)據(jù)庫的升級問題。
- 修改gradle文件
首先在module的gradle文件中修改版本號:
//改為最新的版本號
schemaVersion 2
如果只是做了上面的步驟則會(huì)默認(rèn)清除所有數(shù)據(jù),一看源碼便知,當(dāng)檢測到version變化的時(shí)候便執(zhí)行dropAllTables()操作,再重新建庫
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
數(shù)據(jù)遷移的核心思想:
1 把舊表改為臨時(shí)表
2 建立新表
3 臨時(shí)表數(shù)據(jù)寫入新表,刪除臨時(shí)表
站在巨人的肩膀上,這里直接使用了開源的庫,配合greenDAO來做數(shù)據(jù)遷移,親測穩(wěn)定:
GreenDaoUpgradeHelper
schemaVersion 版本加1,User類新增屬性:major
不做遷移處理前,重新安裝后數(shù)據(jù)庫已經(jīng)被重置,數(shù)據(jù)為空。遷移配置后,舊表數(shù)據(jù)已經(jīng)被存到新表中,major字段為null;
使用方式該git上面介紹的很詳細(xì)了,不再贅述。
感謝前輩們的無私分享。