GreenDao簡單使用


 

  greenDAO是Android的對象/關系映射(ORM)工具。它為關系數據庫SQLite提供了面向對象的接口。像greenDAO這樣的ORM工具可以為您完成許多重復性任務,並為您的數據提供簡單的界面。

使用GreenDao的優點

1 只需要定義數據模型,GreenDao框架將創建數據實例和DAO(數據訪問對象),能夠節省部分代碼

2使用GreenDao大多數屍體可以以每秒幾千個實體的速率進行插入,更新和加載

3.GreenDao支持加密數據庫來保護敏感數據

4.微小的依賴庫,GreenDao的關鍵依賴庫大小不超過100kb

5.如果需要,實體可以被激活。而活動實體可以透明的解析關系,並且有更新/刪除/刷新方法,以便訪問持久性功能

6.GreenDao允許你將協議緩沖區對象直接保存到數據庫中,如果你通過protobuf通話到你的服務器則不需要另一個映射。常規實體的所有持久性操作都可以用於protobuf對象。

7.自動生成代碼,我們需要關注實體類以及Dao,因為GreenDao已經幫我們生成了。

8.開源

 

GreenDao對外提供的核心類

1 DaoMaster

  保存數據庫對象 SQLiteDatabase 並管理特定模式的Dao類。它具有靜態方法來創建表或將他們刪除。其內部類OpenHelper和DevOpenHelper時SQLite數據庫中創建模式的SQLiteOpenHelper實現

2 DaoSession

  管理特定模式的所有可用Dao對象,可以使用其中一個getter方法獲取,DaoSession還為實體提供了一些通用的持久性方法如插入、加載、更新、刷新、刪除。最后Daosession對象也跟蹤一個身份范圍

3 Dao層

  數據訪問對象Dao持續存在並查詢實體。對於每個實體,GreenDao生成一個Dao,它比DaoSesssion有更多的持久化方法,例如:count,loadAll,insertInTx

4. 實體

  持久對象,通常實體時使用標准java屬性如POJO或JavaBean來表示數據庫的對象

 

關於注解的解釋:

Entity注釋將Java類標記為greenDAO的可預設實體。即生成數據庫中的一個表

Id注釋選擇long / Long屬性作為實體ID。在數據庫方面,它是主鍵。參數autoincrement是一個標志,用於使ID值不斷增加(不重用舊值)。 

@Property

設置一個非默認關系映射所對應的列名,默認是使用字段名,例如:@Property(nameInDb = “userName”)

@NotNull

設置數據庫表當前列不能為空

@Transient

添加此標記后不會生成數據庫表的列

@Unique

表名該屬性在數據庫中只能有唯一值

@ToMany

定義一對多個實體對象的關系

@ToOne

表示一對一關系

@OrderBy

更加某一字段排序 ,例如:@OrderBy(“date ASC”)

 

下面進入GreenDao的使用

1 配置環境,添加依賴

在工程目錄下build.gradle下dependencies添加插件

buildscript {
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.2'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // 添加GreenDao插件
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

在app的build.gradle文件下進行如下配置

apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // greendao
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
   
}

dependencies {
    implementation 'org.greenrobot:greendao:3.2.2' // add library

}
greendao {
    schemaVersion 2//指定數據庫schema版本號,遷移等操作會用到;
  daoPackage 'com.example.greendaodemo1' //dao的包名,包名默認是entity所在的包;
  targetGenDir 'src/main/java'//生成數據庫文件的目錄;
 }

 

2. 新建實體類用@Entity注解,實體類中的屬性即為數據庫中對應的字段,最后build項目機會生成相應的代碼

 

@Entity
public class StudentBean {
    private String name;
    private int age;
    private String gender;
}

 

build以后生成如下文件

 

 

3 GreenDao初始化

在Application中位置一個全局的會話

獲取DaoSession 

public class MyApplication extends Application {
    private DaoSession daoSession;
    @Override
    public void onCreate() {
        super.onCreate();
        initGreenDao();
    }
    private void initGreenDao()
    {
        //先通過DaoMaster的DevOpenHelper方法來創建一個數據庫
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,"student.db");
        //獲得一個db
        SQLiteDatabase db = helper.getWritableDatabase();
        //新建一個DaoMaster,獲得master
        DaoMaster daoMaster = new DaoMaster(db);
        //通過master new一個Daosession
        daoSession = daoMaster.newSession();
    }
    public DaoSession getDaoSession()
    {
        return daoSession;
    }
}

獲取StudentBeanDao

studentDao = daoSession.getStudentBeanDao();

 

4 實現

1.插入

  • insert(User entity): 插入一條記錄, 當指定主鍵在表中存在時會發生異常
  • insertOrReplace(User entity) : 當指定主鍵在表中存在時會覆蓋數據,有該數據時則更新,推薦同步數據庫時使用該方法
  • save(User entity): save 類似於insertOrReplace,區別在於save會判斷傳入對象的key,有key的對象執行更新,無key的執行插入。當對象有key但並不在數據庫時會執行失敗.適用於保存本地列表。
//save的源碼
public
void save(T entity) { if (hasKey(entity)) { update(entity); } else { insert(entity); } }

 

public void inserOrReplace(StudentBean student)
{
daoSession.insertOrReplace(student);
}

 

StudentBean student = new StudentBean();
student.setId(1);
student.setName("李四");
student.setAge(12);
student.setGender("男");
//insertData(student);
inserOrReplace(student);

其他一些插入方法

insertInTx(T... entities):使用事務在數據庫中插入給定的實體。
insertInTx(Iterable<T> entities):使用事務操作,將給定的實體集合插入數據庫。
insertInTx(Iterable<T> entities, boolean setPrimaryKey):使用事務操作,將給定的實體集合插入數據庫,並設置是否設定主鍵 。

insertOrReplaceInTx(T... entities):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋
insertOrReplaceInTx(Iterable<T> entities):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋 。
insertOrReplaceInTx(Iterable<T> entities, boolean setPrimaryKey):使用事務操作,將給定的實體插入數據庫,若此實體類存在,則覆蓋,並設置是否設定主鍵 。
insertWithoutSettingPk(T entity):將給定的實體插入數據庫,但不設定主鍵。

// 新增數據插入相關API
save(T entity):將給定的實體插入數據庫
saveInTx(Iterable<T> entities):將給定的實體集合插入數據庫
saveInTx(T... entities):使用事務操作,將給定的實體插入數據庫

2.查詢

        List<StudentBean> students = studentDao.loadAll();
        StudentBean students2 = studentDao.load(1L);
        StudentBean students3 = studentDao.loadByRowId(0L);

條件查詢

//查詢全部
List<User> list = mUserDao.queryBuilder().list();

//查詢 name等於xyh8的數據
List<User> list= mUserDao.queryBuilder().where(UserDao.Properties.Name.eq("xyh8")).list();

//查詢 name不等於xyh8的數據
List<User> list= mUserDao.queryBuilder().where(UserDao.Properties.Name.notEq("xyh8")).list();

//like  模糊查詢
//查詢 name以xyh3開頭的數據
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Name.like("xyh3%")).list();

//between 區間查詢 年齡在20到30之間
 List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.between(20,30)).list();

//gt: greater than 半開區間查詢,年齡大於18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.gt(18)).list();

//ge: greater equal 半封閉區間查詢,年齡大於或者等於18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.ge(18)).list();

//lt: less than 半開區間查詢,年齡小於18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.lt(18)).list();

//le: less equal 半封閉區間查詢,年齡小於或者等於18
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Age.le(18)).list();

//排序

//名字以xyh8開頭,年齡升序排序
 List<User> list = mUserDao.queryBuilder()
                .where(UserDao.Properties.Name.like("xyh8%"))
                .orderAsc(UserDao.Properties.Age)
                .list();

//名字以xyh8開頭,年齡降序排序
 List<User> list = mUserDao.queryBuilder()
                .where(UserDao.Properties.Name.like("xyh8%"))
                .orderDesc(UserDao.Properties.Age)
                .list();

3 更新

update(T entity) :更新給定的實體

updateInTx(Iterable<T> entities) :使用事務操作,更新給定的實體

updateInTx(T... entities):使用事務操作,更新給定的實體
       studentDao.update(student);
        studentDao.updateInTx(student);

4 刪除

//刪除全部
 mUserDao.deleteAll();

delete(T entity):從數據庫中刪除給定的實體

deleteByKey(K key):從數據庫中刪除給定Key所對應的實體

deleteInTx(T... entities):使用事務操作刪除數據庫中給定的實體

deleteInTx(<T> entities):使用事務操作刪除數據庫中給定實體集合中的實體

deleteByKeyInTx(K... keys):使用事務操作刪除數據庫中給定的所有key所對應的實體

deleteByKeyInTx(Iterable<K> keys):使用事務操作刪除數據庫中給定的所有key所對應的實體
public void delete(StudentBean student)
    {
        studentDao.delete(student);
    }

 

5 封裝

 

package com.example.greendaodemo1;

import android.content.Context;

public class DaoManager {

    private Context mContext;

    //創建數據庫的名字
    private static final String DB_NAME = "MyGreenDb.db";

    //多線程中要被共享的使用volatile關鍵字修飾  GreenDao管理類
    private volatile static DaoManager mInstance;

    //它里邊實際上是保存數據庫的對象
    private static DaoMaster mDaoMaster;

    //創建數據庫的工具
    private static DaoMaster.DevOpenHelper mHelper;

    //管理gen里生成的所有的Dao對象里邊帶有基本的增刪改查的方法
    private static DaoSession mDaoSession;


    private DaoManager() {
    }

    /**
     * 單例模式獲得操作數據庫對象
     *
     * @return
     */
    public static DaoManager getInstance() {
        if (mInstance == null) {
            synchronized (DaoManager.class) {
                if (mInstance == null) {
                    mInstance = new DaoManager();
                }
            }
        }
        return mInstance;
    }
    /**
     * 初始化上下文創建數據庫的時候使用
     */
    public void init(Context context) {
        this.mContext = context;
    }

    /**
     * 判斷是否有存在數據庫,如果沒有則創建
     *
     * @return
     */
    public DaoMaster getDaoMaster() {
        if (mDaoMaster == null) {
            mHelper = new DaoMaster.DevOpenHelper(mContext, DB_NAME, null);
            mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());
        }
        return mDaoMaster;
    }

    /**
     * 完成對數據庫的添加、刪除、修改、查詢操作,
     *
     * @return
     */
    public DaoSession getDaoSession() {
        if (mDaoSession == null) {
            if (mDaoMaster == null) {
                mDaoMaster = getDaoMaster();
            }
            mDaoSession = mDaoMaster.newSession();
        }
        return mDaoSession;
    }

    /**
     * 關閉所有的操作,數據庫開啟后,使用完畢要關閉
     */
    public void closeConnection() {
        closeHelper();
        closeDaoSession();
    }

    public void closeHelper() {
        if (mHelper != null) {
            mHelper.close();
            mHelper = null;
        }
    }

    public void closeDaoSession() {
        if (mDaoSession != null) {
            mDaoSession.clear();
            mDaoSession = null;
        }
    }
}

 

 6 數據庫升級

 比如需要在實體類加一個字段 或者 改變字段屬性等 就需要版本更新來保存以前的數據了;

思路:創建臨時表–>刪除原表–>創建新表–>復制臨時表數據到新表並刪除臨時表;這樣數據庫表的更新就完成了

  • 1、MigrationHelper:
package com.example.greendaodemo1;

import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;

import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.internal.DaoConfig;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MigrationHelper {

    private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";

    private static MigrationHelper instance;

    public static MigrationHelper getInstance() {
        if (instance == null) {
            instance = new MigrationHelper();
        }
        return instance;
    }

    public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {

        generateTempTables(db, daoClasses);
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
        restoreData(db, daoClasses);
    }

    /**
     * 生成臨時列表
     *
     * @param db
     * @param daoClasses
     */
    private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            String divider = "";
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList<>();

            StringBuilder createTableStringBuilder = new StringBuilder();

            createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tableName).contains(columnName)) {
                    properties.add(columnName);

                    String type = null;

                    try {
                        type = getTypeByClass(daoConfig.properties[j].type);
                    } catch (Exception exception) {
                        exception.printStackTrace();
                    }

                    createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                    if (daoConfig.properties[j].primaryKey) {
                        createTableStringBuilder.append(" PRIMARY KEY");
                    }

                    divider = ",";
                }
            }
            createTableStringBuilder.append(");");

            db.execSQL(createTableStringBuilder.toString());

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tableName).append(";");

            db.execSQL(insertTableStringBuilder.toString());

        }
    }

    /**
     * 存儲新的數據庫表 以及數據
     *
     * @param db
     * @param daoClasses
     */
    private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList();

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tempTableName).contains(columnName)) {
                    properties.add(columnName);
                }
            }

            StringBuilder insertTableStringBuilder = new StringBuilder();

            insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(") SELECT ");
            insertTableStringBuilder.append(TextUtils.join(",", properties));
            insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");

            StringBuilder dropTableStringBuilder = new StringBuilder();
            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
            db.execSQL(insertTableStringBuilder.toString());
            db.execSQL(dropTableStringBuilder.toString());
        }
    }

    private String getTypeByClass(Class<?> type) throws Exception {
        if (type.equals(String.class)) {
            return "TEXT";
        }
        if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
            return "INTEGER";
        }
        if (type.equals(Boolean.class)) {
            return "BOOLEAN";
        }

        Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
        exception.printStackTrace();
        throw exception;
    }

    private List<String> getColumns(Database db, String tableName) {
        List<String> columns = new ArrayList<>();
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
            if (cursor != null) {
                columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
            }
        } catch (Exception e) {
            Log.v(tableName, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return columns;
    }
}
  • 2.由於升級數據庫需要在DevOpenHelper類的onUpgrade()方法里面繼續,因此我們需要自定義一個類繼承DevOpenHelper重寫onUpgrade()方法
/**
 * 自定義  MySQLiteOpenHelper繼承DaoMaster.OpenHelper 重寫更新數據庫的方法
 * <p>
 * 當app下的build.gradle  的schemaVersion數據庫的版本號改變時,創建數據庫會調用onUpgrade更細數據庫的方法
 * <p>
 */

public class MyDevOpenHelper extends DaoMaster.DevOpenHelper {

    public MyDevOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    /**
     * 數據庫升級
     *
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        //super.onUpgrade(db, oldVersion, newVersion);

        //操作數據庫的更新 有幾個表升級都可以傳入到下面
        MigrationHelper.getInstance().migrate(db, UserDao.class);
    }
}
  • .3 修改在項目根目錄build.gradle文件中配置的數據庫版本號(新版本號一定要比老版本大)
greendao {
    schemaVersion 6
    daoPackage 'com.example.greendaodemo1'
    targetGenDir 'src/main/java'
}

在StudentBean中新增一個字段我們新增的字段和修改的字段最好為String類型,避免字段不能為null的情況發生

代碼: GitHub

 

添加依賴

implementation "net.zetetic:android-database-sqlcipher:3.5.2"
DaoMaster.DevOpenHelper a = new DaoMaster.DevOpenHelper(this,"database_name",null);
try {
    daoSession = new DaoMaster(a.getEncryptedWritableDb(MY_PWD)).newSession();
    daoSession.getUserDao().insert(man1);

}catch (Exception e){
    Log.d("e", String.valueOf(e));
}

 

參考博文:https://www.cnblogs.com/WUXIAOCHANG/p/10673557.html

    https://blog.csdn.net/qq_36699930/article/details/81540781


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM