GreenDao 初体验

GreenDao 使用

环境搭建(android studio)

project的build.gradle

buildscript {
    
    repositories {
        google()
        jcenter()
        //maven 仓库
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.2'
        //GreenDao 的插件
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

app的build.gradle

apply plugin: 'com.android.application'
//使用GreenDao 的插件
apply plugin: 'org.greenrobot.greendao'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.test.greendao"
        minSdkVersion 23
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

//添加自动生成代码的部分,在构建工程部分使用
greendao{
    //设置数据库的版本
    schemaVersion 1
    //设置DaoMaster,DaoSession,Dao包名,
    daoPackage 'com.test.greendao.dao'
    targetGenDir 'src/main/java'
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    //GreenDao 依赖
    implementation 'org.greenrobot:greendao:3.2.2'
    //GreenDao 自动生成代码的依赖,没有使用到
    //implementation 'org.greenrobot:greendao-generator:3.2.2'
}

编写自己的实体类

//使用Entity注解标识这个实体类和数据库表的关系
@Entity
public class Student {
    //使用Id注解标识这个字段在数据库表结构中是主键,自增的
    @Id
    private Long id;
    private String name;
    private String email;
    private Integer age;
}

构建工程

选择Build->Make Project,会自动生成一些类,比如我们当前项目中的实体类是Student,那么会生成如下的类
DaoMaster
DaoSession
StudentDao
并将Student类中的get,set方法进行补全,并生成2个构造方法
生成类的配置在app的build.gradle文件中的greendao的任务中进行了配置

使用生成的类操作数据库

配置全局的DaoMaster,DaoSession等信息

创建DbManager类来管理数据库相关的类,DaoMaster,DaoSession,xxxDao等

public class DbManager {
    //是否加密,当前没有处理加密
    private static final boolean ENCRYPTED = true;
    //数据库名
    private static final String DB_NAME = "test.db";
    private static DbManager dbManager;
    private static DaoMaster.DevOpenHelper helper;
    private static DaoMaster daoMaster;
    private static DaoSession daoSession;
    private Context mContext;

    private DbManager(Context context){
        this.mContext =context;
        //初始化数据库信息
        helper = new DaoMaster.DevOpenHelper(context,DB_NAME);
        getDaoMaster(mContext);
        getDaoSession(mContext);
    }

    public static DbManager getInstance(Context context){
        if(null == dbManager){
            synchronized (DbManager.class){
                if(null == dbManager){
                    dbManager = new DbManager(context);
                }
            }
        }
        return dbManager;
    }

    public static SQLiteDatabase getReadableDatabase(Context context){
        if(null == helper){
            getInstance(context);
        }
        return helper.getReadableDatabase();
    }

    public static SQLiteDatabase getWritableDatabase(Context context){
        if(null == helper){
            getInstance(context);
        }
        return helper.getWritableDatabase();
    }

    public static DaoMaster getDaoMaster(Context context) {
        if(null == daoMaster){
            synchronized (DbManager.class){
                if(null == daoMaster){
                    daoMaster = new DaoMaster(getWritableDatabase(context));
                    //数据库升级,降级操作使用下面的方法
                    //MyOpenHelper helper = new MyOpenHelper(context,DB_NAME);
                    //daoMaster = new DaoMaster(helper.getWritableDb());
                }
            }
        }
        return daoMaster;
    }

    public static DaoSession getDaoSession(Context context) {
        if(null == daoSession){
            synchronized (DbManager.class){
                daoSession = getDaoMaster(context).newSession();
            }
        }
        return daoSession;
    }

}

数据库的升级降级操作

数据库升级的原理

创建临时表
将原始表中数据转移到临时表中
删除原始表
创建新表
将临时表中数据转移到新表中
删除临时表

需要的类

MigrationHelper

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;
    }
}

MyOpenHelper继承自DaoMaster.OpenHelper

public class MyOpenHelper extends DaoMaster.OpenHelper {
    public MyOpenHelper(Context context, String name) {
        super(context, name);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        super.onUpgrade(db, oldVersion, newVersion);
        //操作数据库的更新 有几个表升级都可以传入到下面  
        Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
        if (oldVersion < newVersion) {
            Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
            MigrationHelper.getInstance().migrate(db, StudentDao.class);
            //更改过的实体类(新增的不用加)   更新UserDao文件 可以添加多个  XXDao.class 文件  
            //MigrationHelper.getInstance().migrate(db, UserDao.class,XXDao.class);  
        }
        //MigrationHelper.getInstance().migrate(db,StudentDao.class);
    }
}

小坑

运行时,操作数据库会报这个错

org.greenrobot.greendao.database.DatabaseOpenHelper$EncryptedHelper>: java.lang.NoClassDefFoundError: Failed resolution of: Lnet/sqlcipher/database/SQLiteOpenHelper;

实际是缺少了加密的组件依赖,并不影响实际的运行,为了消除错误信息,在app的build.gradle文件中加入如下代码

implementation 'net.zetetic:android-database-sqlcipher:3.5.2'
posted @ 2018-06-08 21:07  真菜啊  阅读(338)  评论(0编辑  收藏  举报