美文网首页
GreenDao3.2.2

GreenDao3.2.2

作者: ForeverValid | 来源:发表于2017-10-30 16:33 被阅读0次

    官网: http://greenrobot.org/greendao

    API文档:http://greenrobot.org/greendao/documentation

    更新日志:http://greenrobot.org/greendao/changelog

    GitHub源码地址:https://github.com/greenrobot/greendao

    GreenDao 简介
    greenDAO是一个开源的Android ORM,使SQLite数据库的开发再次有趣。
    它减轻开发人员处理低级数据库需求,同时节省开发时间。
    
    SQLite是一个令人敬畏的嵌入式关系数据库。
    然而,编写SQL和解析查询结果是相当乏味和耗时的任务。
    
    通过将Java对象映射到数据库表(称为ORM,“对象/关系映射”),
    greenDAO可以将它们从这些映射中释放出来。
    这样,您可以使用简单的面向对象的API来存储,更新,删除和查询Java对象。
    
    GreenDao 优势
    1.最高性能(可能是Android最快的ORM); 我们的基准也是开源的
    2.易于使用的功能强大的API涵盖关系和联接
    3.内存消耗最小
    4.GreenDAO核心库(<100KB),不会影响Apk的大小。
    5.数据库加密:greenDAO支持SQLCipher,以保护用户的数据安全
    6.强大的社区:超过5.000 GitHub明星表明有一个强大和积极的社区
    
    GreenDao 的项目配置

    在项目的Android的build.gradle(Module:app) 文件中的dependencies标签下添加

    dependencies {
    compile'org.greenrobot:greendao:3.2.2'
    compile'org.greenrobot:greendao-generator:3.2.2'
    }
    

    在项目的Android的build.gradle(Module:app) 文件中的顶部添加插件代码

    apply plugin: 'org.greenrobot.greendao'
    

    在项目的Android的build.gradle(Module:app) 文件中的android标签下添加

    //自定义路径
        greendao {
            schemaVersion 1//当前版本的数据库模式。这被OpenHelpers类用于在模式版本之间迁移。如果更改了实体/数据库模式,则必须增加该值。默认为1。
            daoPackage 'com.anye.greendao.gen'//生成的Dao,DaoMaster和DaoSession的包名称。 默认为源实体的包名称。
            targetGenDir 'src/main/java'//生成源码存储的位置。 默认为构建目录( build/generated/source/greendao)中生成的源文件夹。
            generateTest true //设置为true以自动生成单元测试。
            targetGenDirTests 'src/androidTest/java'//应存储生成的单元测试的基本目录。默认为src/androidTest/java。
        }
    

    build.gradle(Module:app)具体位置如下:

    //GreenDao
    apply plugin: 'org.greenrobot.greendao'
    android {
        compileSdkVersion 26
        defaultConfig {
            applicationId "com.example.administrator.greendao"
            minSdkVersion 15
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        //GreenDao
        greendao {
            schemaVersion 1
            daoPackage 'com.anye.greendao.gen'//注意根据自己的包名路径.gen
            targetGenDir 'src/main/java'
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.0.2'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.1'
        androidTestImplementation 
       'com.android.support.test.espresso:espresso-core:3.0.1'
        //GreenDao
        compile'org.greenrobot:greendao:3.2.2'
        compile'org.greenrobot:greendao-generator:3.2.2'
    }
    

    在项目的Android的build.gradle(Project:appName)文件中的dependencies标签下添加

    classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'    
    

    build.gradle(Project:appName)具体位置如下:

    buildscript { 
        repositories { 
              jcenter()
    }    
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        //GreenDao
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'    
        }
    }
    
    GreenDao使用
    public class MyApplication extends Application {
     private DaoMaster.DevOpenHelper mHelper;
     private SQLiteDatabase db;
     private DaoMaster mDaoMaster;
     private DaoSession mDaoSession;
     public static MyApplication instances;
     @Override   
     public void onCreate() {
         super.onCreate();
         instances = this;
         setDatabase();
     }
     public static MyApplication getInstances(){
         return instances;
     }
    
    /**
     * 设置greenDao
     */
    private void setDatabase() {
        // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。
        // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。
        // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
        // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
        mHelper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
        db = mHelper.getWritableDatabase();
        // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。 
        mDaoMaster = new DaoMaster(db); 
        mDaoSession = mDaoMaster.newSession();
    }
    public DaoSession getDaoSession() {
          return mDaoSession;
    }
    public SQLiteDatabase getDb() {
          return db;
      }
    }
    

    创建一个User的实体类

    @Entity
    public class User {
        @Id(autoincrement = true)
        private Long id; 
        @Transient 
        private int tempUsageCount; // not persisted  
    }
    

    注释说明

    @Entity  
    实体注解
    @Id
    主键 Long型,可以通过@Id(autoincrement = true)设置自增长。
    通过这个注解标记的字段必须是Long,数据库中表示它就是主键,并且默认是自增的。
    @transient 
    就是在给某个javabean上需要添加个属性,但是这个属性你又不希望给存到数据库中去。
    仅仅是做个临时变量,用一下。
    不修改已经存在数据库的数据的数据结构。
    那么这个注解就可以一用。
    只要在你准备添加的临时属性上添加这个注解,然后getter和setter自动完成一下,就可以啦。
    

    MakeProject

    按压F9编译项目,User实体类会自动编译,生成get、set方法并且会在com.anye.greendao.gen目录下生成三个文件;

    GreenDao自动生成目录.png

    获取UserDao对象:

      mUserDao = MyApplication.getInstances().getDaoSession().getUserDao();
    

    具体位置如下:

    pravite UserDao mUserDao;
    public class MainActivity extends Activity{
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     mUserDao=MyApplication.getInstances().getDaoSession().getUserDao();
        }
    }
    

    简单的增删改查实现:


    1. 注意:Long型id,如果传入null,则GreenDao会默认设置自增长的值。

    插入单条数据

     insert(User entity):插入一条记录
     insertOrReplace(User entity):插入或替换一条记录
    

    插入多条数据

    insertInTx(userList):插入多条记录
    insertOrReplaceInTx(userList):插入多条记录或替换一条记录
    
    增.png

    2.删

    deleteBykey(Long key) :根据主键删除一条记录。
    deleteInTx(userList):删除多条记录 
    delete(User entity) :根据实体类删除一条记录,一般结合查询方法,查询出一条记录之后删除。
    deleteAll(): 删除所有记录。
    
    删.png

    3.改

    update(User entity):更新一条记录
    updateInTx(userList):更新多条记录
    
    改.png
    loadAll()或queryBuilder().list():查询所有记录
    load(Long key):根据主键查询一条记录
    queryBuilder().list():返回:List
    queryBuilder().where(UserDao.Properties.Name.eq("")).list():返回:List
    queryRaw(String where,String selectionArg):返回:List
    

    单个条件

    where() 
    whereOr()
    

    多个条件

    where(,,) 
    whereOr(,,)
    

    降序

    orderDesc() 
    

    升序

    orderAsc() 
    

    当页限制个数

    limit() 
    

    根据key查询

    load(key)
    

    更多的操作就不一一介绍了,大家可以根据需要去查找资料;

    数据库升级

    实现思路

    1、创建临时表temporary,将原先表数据迁移过去
    2、删除所有原表
    3、创建新表
    4、将temporary表数据复制到新表,最后将temporary表删除
    

    创建一个类MigrationHelper:

    public final class MigrationHelper {
    
        public static boolean DEBUG = false;
        private static String TAG = "MigrationHelper";
        private static final String SQLITE_MASTER = "sqlite_master";
        private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";
    
        public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
            Database database = new StandardDatabase(db);
    
            printLog("【The Old Database Version】" + db.getVersion());
            printLog("【Generate temp table】start");
            generateTempTables(database, daoClasses);
            printLog("【Generate temp table】complete");
    
            dropAllTables(database, true, daoClasses);
            createAllTables(database, false, daoClasses);
    
            printLog("【Restore data】start");
            restoreData(database, daoClasses);
            printLog("【Restore data】complete");
        }
    
        private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
            for (int i = 0; i < daoClasses.length; i++) {
                String tempTableName = null;
    
                DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
                String tableName = daoConfig.tablename;
                if (!isTableExists(db, false, tableName)) {
                    printLog("【New Table】" + tableName);
                    continue;
                }
                try {
                    tempTableName = daoConfig.tablename.concat("_TEMP");
                    StringBuilder dropTableStringBuilder = new StringBuilder();
                    dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");
                    db.execSQL(dropTableStringBuilder.toString());
    
                    StringBuilder insertTableStringBuilder = new StringBuilder();
                    insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);
                    insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
                    db.execSQL(insertTableStringBuilder.toString());
                    printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));
                    printLog("【Generate temp table】" + tempTableName);
                } catch (SQLException e) {
                    Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);
                }
            }
        }
    
        private static boolean isTableExists(Database db, boolean isTemp, String tableName) {
            if (db == null || TextUtils.isEmpty(tableName)) {
                return false;
            }
            String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;
            String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?";
            Cursor cursor=null;
            int count = 0;
            try {
                cursor = db.rawQuery(sql, new String[]{"table", tableName});
                if (cursor == null || !cursor.moveToFirst()) {
                    return false;
                }
                count = cursor.getInt(0);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return count > 0;
        }
    
    
        private static String getColumnsStr(DaoConfig daoConfig) {
            if (daoConfig == null) {
                return "no columns";
            }
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < daoConfig.allColumns.length; i++) {
                builder.append(daoConfig.allColumns[i]);
                builder.append(",");
            }
            if (builder.length() > 0) {
                builder.deleteCharAt(builder.length() - 1);
            }
            return builder.toString();
        }
    
    
        private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
            reflectMethod(db, "dropTable", ifExists, daoClasses);
            printLog("【Drop all table】");
        }
    
        private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
            reflectMethod(db, "createTable", ifNotExists, daoClasses);
            printLog("【Create all table】");
        }
    
        /**
         * dao class already define the sql exec method, so just invoke it
         */
        private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
            if (daoClasses.length < 1) {
                return;
            }
            try {
                for (Class cls : daoClasses) {
                    Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
                    method.invoke(null, db, isExists);
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
        private static 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");
    
                if (!isTableExists(db, true, tempTableName)) {
                    continue;
                }
    
                try {
                    // get all columns from tempTable, take careful to use the columns list
                    List<String> columns = getColumns(db, tempTableName);
                    ArrayList<String> properties = new ArrayList<>(columns.size());
                    for (int j = 0; j < daoConfig.properties.length; j++) {
                        String columnName = daoConfig.properties[j].columnName;
                        if (columns.contains(columnName)) {
                            properties.add(columnName);
                        }
                    }
                    if (properties.size() > 0) {
                        final String columnSQL = TextUtils.join(",", properties);
    
                        StringBuilder insertTableStringBuilder = new StringBuilder();
                        insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
                        insertTableStringBuilder.append(columnSQL);
                        insertTableStringBuilder.append(") SELECT ");
                        insertTableStringBuilder.append(columnSQL);
                        insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
                        db.execSQL(insertTableStringBuilder.toString());
                        printLog("【Restore data】 to " + tableName);
                    }
                    StringBuilder dropTableStringBuilder = new StringBuilder();
                    dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
                    db.execSQL(dropTableStringBuilder.toString());
                    printLog("【Drop temp table】" + tempTableName);
                } catch (SQLException e) {
                    Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);
                }
            }
        }
    
        private static List<String> getColumns(Database db, String tableName) {
            List<String> columns = null;
            Cursor cursor = null;
            try {
                cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
                if (null != cursor && cursor.getColumnCount() > 0) {
                    columns = Arrays.asList(cursor.getColumnNames());
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (cursor != null)
                    cursor.close();
                if (null == columns)
                    columns = new ArrayList<>();
            }
            return columns;
        }
    
        private static void printLog(String info){
            if(DEBUG){
                Log.d(TAG, info);
            }
        }
    
    }
    

    自定义一个OpentHelper类继承于DaoMaster.OpenHelper类:

    public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
    
        public MySQLiteOpenHelper(Context context, String name) {
            super(context, name);
        }
    
        public MySQLiteOpenHelper(Context context, String name,
                                SQLiteDatabase.CursorFactory factory) {
            super(context, name, factory);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            MigrationHelper.migrate(db,
                    ProjectListDao.classUserListDao.class);//数据版本变更才会执行
        }
    
    }
    

    在DaoMaster类的onUpgrade方法添加如下代码即可,参数为所有的Dao类:

     @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            MigrationHelper.migrate(db,“所有的Dao类”);//数据版本变更才会执行
        }
    

    这样数据库升级后以前的数据就不会丢失了,当然如果数据库升级后数据初始化,重新获取,不影响项目功能,可以不用考虑此方法。

    GreenDao的代码混淆
    -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
    public static java.lang.String TABLENAME;
    }
    -keep class **$Properties
    
    # If you do not use SQLCipher:
    -dontwarn org.greenrobot.greendao.database.**
    # If you do not use RxJava:
    -dontwarn rx.**
    

    相关文章

      网友评论

          本文标题:GreenDao3.2.2

          本文链接:https://www.haomeiwen.com/subject/iktmpxtx.html