GreenDao3.2.2集成使用以及数据库的升级

来源:互联网 发布:ssh安装 centos 编辑:程序博客网 时间:2024/06/06 01:50

                                  GreenDao3.2.2集成使用以及数据库的升级

一概念
     是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。
                                                     
二优点:
     一个精简的库;性能最大化;内存开销最小化;易于使用的 APIs;对 Android 进行高度优化。
三集成
    1在app的build.gradle  红色的是要添加的
apply plugin: 'com.android.application'apply plugin: 'org.greenrobot.greendao' // apply pluginandroid {       //初始化greendao基本信息    greendao{        schemaVersion 1        daoPackage 'com.admom.mygreendaotest.gen'        targetGenDir 'src/main/java'    }//schemaVersion: 数据库schema版本,也可以理解为数据库版本号//daoPackage:设置DaoMaster、DaoSession、Dao包名//targetGenDir:设置DaoMaster、DaoSession、Dao目录//targetGenDirTest:设置生成单元测试目录//generateTests:设置自动生成单元测试用例}dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        exclude group: 'com.android.support', module: 'support-annotations'    })    compile 'com.android.support:appcompat-v7:25.3.1'    compile 'com.android.support.constraint:constraint-layout:1.0.2'    testCompile 'junit:junit:4.12'    compile 'org.greenrobot:greendao:3.2.2'}
    2在工程的build.gradle里添加如下代码
buildscript {    repositories {        jcenter()        mavenCentral() // add repository    }    dependencies {        classpath 'com.android.tools.build:gradle:2.3.2'        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}
   3根据
greendao{        schemaVersion 1        daoPackage 'com.example.wbxu.gen'        targetGenDir 'src/main/java'    }
的配置  在src/java/ com.example.wbxu   这个包的下边创建gen用于存放DaoMaster DaoSession  Dao【操作表的根据bean生成的】,
    4创建实体类bean
  
@Entitypublic class Fruit {    @Id(autoincrement = true)   //设置主键自增长    private Long id;   //自增id必须为long类型的    private String Name;  //名字    @NotNull    private int Count; //个数}


然后点击Build  Make Project   就会在gen文件夹里生成DaoMaster  DaoSession   对应实体【对应表的Dao】
    5编写DaoManager创建数据库、创建数据库表、包含增删改查的操作
   
public class DaoManager {    private static final String TAG = DaoManager.class.getSimpleName();    //创建数据库的名字    private static final String DB_NAME = "MyGreenDb.db";    //初始化上下文    private Context context;    //多线程中要被共享的使用volatile关键字修饰  GreenDao管理类    private volatile static DaoManager mInstance;    //它里边实际上是保存数据库的对象    private static DaoMaster mDaoMaster;    //创建数据库的工具    private static DaoMaster.DevOpenHelper mHelper;    //管理gen里生成的所有的Dao对象里边带有基本的增删改查的方法    private static DaoSession mDaoSession;    /**     * 单例模式获得操作数据库对象     * @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.context = context;    }    /**     * 判断是否有存在数据库,如果没有则创建     * @return     */    public DaoMaster getDaoMaster(){        if(mDaoMaster == null) {            mHelper = new DaoMaster.DevOpenHelper(context, 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编写对应表的工具类  实现操作该表的方法
    
public class FruitDaoUtil {    private DaoManager mManager;    private String TAG="flag";    //操作Fruit的构造函数    public FruitDaoUtil(Context context) {        mManager = DaoManager.getInstance();        mManager.init(context);    }    /**     * 完成fruit记录的插入,如果表未创建,先创建fruit表     *     * @param fruit     * @return  返回long值 -1为失败     */    public boolean insertFruit(Fruit fruit) {        boolean flag = false;        flag = mManager.getDaoSession().getFruitDao().insertOrReplace(fruit) == -1 ? false : true;        Log.i(TAG, "-------插入一条的结果为"+flag);        return flag;    }    /**     * 插入多条数据,在子线程操作     * @return     */    public boolean insertListFruit(final List<Fruit> mList) {        boolean flag = false;        try {            mManager.getDaoSession().runInTx(new Runnable() {                @Override                public void run() {                    for (Fruit fruit : mList) {                        mManager.getDaoSession().insertOrReplace(fruit);                    }                }            });            flag = true;        } catch (Exception e) {            e.printStackTrace();        }        return flag;    }    /**     *   刷新指定数据     */    public boolean reFreshFruit(Fruit fruit){        boolean flag = false;        mManager.getDaoSession().refresh(fruit);        return flag;    }    /**     * 修改一条数据     * @return     */    public boolean updateFruit(Fruit fruit){        boolean flag = false;        try {            mManager.getDaoSession().update(fruit);            flag = true;        }catch (Exception e){            e.printStackTrace();        }        return flag;    }    /**     * 删除单条记录     * @return     */    public boolean deleteFruit(Fruit fruit){        boolean flag = false;        try {            mManager.getDaoSession().delete(fruit);            flag = true;        }catch (Exception e){            e.printStackTrace();        }        return flag;    }    /**     * 删除所有记录     * @return     */    public boolean deleteAll(){        boolean flag = false;        try {            mManager.getDaoSession().deleteAll(Fruit.class);            flag = true;        }catch (Exception e){            e.printStackTrace();        }        return flag;    }    /**     * 查询所有记录     * @return     */    public List<Fruit> queryAllFruit(){        return mManager.getDaoSession().loadAll(Fruit.class);    }    /**     * 根据主键id查询记录     * @param key     * @return     */    public Fruit queryFruitById(long key){        return mManager.getDaoSession().load(Fruit.class, key);    }    /**     * 使用 sql语句进行查询操作     *  参数一sql语句  参数二查询条件限定     */    public List<Fruit> queryFruitBySql(String sql, String[] conditions){        return mManager.getDaoSession().queryRaw(Fruit.class, sql, conditions);    }    /**     * 使用queryBuilder进行查询     * @return     */    public List<Fruit> queryFruitByQueryBuilder(long id){        QueryBuilder<Fruit> queryBuilder = mManager.getDaoSession().queryBuilder(Fruit.class);        return queryBuilder.where(FruitDao.Properties.Id.eq(id)).list();    }}
       7测试MainActivity的测试按钮点击事件如下
    
public void onClick(View view) {        switch (view.getId()) {            case R.id.insertsingle:  //插入单个的                mFruitDaoUtil.insertFruit(new Fruit(1L,"苹果1",1));                break;            case R.id.multinsert:  //插入多个的                List<Fruit> list=new ArrayList<Fruit>();                for (int i = 0; i < 10; i++) {                    list.add(new Fruit(Long.parseLong(i+""),"桃子"+i,i));                }                mFruitDaoUtil.insertListFruit(list);                break;            case R.id.refresh:  //刷新单个的                mFruitDaoUtil.reFreshFruit(new Fruit(1L,"苹果1",10));                break;            case R.id.update:  //更新单个的                mFruitDaoUtil.reFreshFruit(new Fruit(1L,"苹果1",20));                break;            case R.id.deletesingle:  //删除单个的                mFruitDaoUtil.deleteFruit(new Fruit(4L,"苹果1",20));                break;            case R.id.deleteMult:  //删除全部                mFruitDaoUtil.deleteAll();                break;            case R.id.checksingle:  //按主键查询一个              Fruit f=  mFruitDaoUtil.queryFruitById(1L);                Log.d("flag","---------按条件查询的结果为"+f.getName()+"-----"+f.getId());                break;            case R.id.checkmult:  //按条件查询              List<Fruit> l=  mFruitDaoUtil.queryFruitBySql("Name,Count",new String[]{"苹果1","1"});                for (int i = 0; i <l.size(); i++) {                    Log.d("flag","---------按条件查询的结果为"+l.get(i).getName()+"-----"+l.get(i).getId());                }                break;            case R.id.querybuilder:  //querybuilder查询                List<Fruit> List  =mFruitDaoUtil.queryFruitByQueryBuilder(1L);                for (int i = 0; i <List.size(); i++) {                    Log.d("flag","---------按条件查询的结果为"+List.get(i).getName()+"-----"+List.get(i).getId());                }                break;            case R.id.upDataDB:                MySQLiteOpenHelper o=new MySQLiteOpenHelper(this,"MyGreenDb.db",null);                DaoMaster daoMaster = new DaoMaster(o.getWritableDatabase());                break;        }}
  四常用的注解解释:
  @Entity                 实体注解
@NotNull              设置表中的当前列的值不为空
@Convert             制定自定义类型
@Generated        GreenDao运行所产生的构造函数或者方法,被此标注的代码可以更新或者下次运行时清除
@Id                       主键Long型,可以通过@Id(autoincrement = true)设置自增长,通过这个注解标记的字段必 须是long,数据库中表示它就是主键,并且默认为自增长
@Index                 使用@Index作为一个属性累创建一个索引,定义多列索引(@Iink Entity#indexes())
@JoinEntity         定义表连接关系
@JoinProperty    定义名称和引用名称属性关系
@Keep                 注解的代码在GreenDao下运行时保持不变
                                      1.注解实体类:默认禁止修改此类
                                      2.注解其他代码,默认禁止修改注解的代码段
@Order                制定排序
@Property           设置一个非默认关系映射所对应的列名,默认使用的字段名。
                              例:@Property(nameInDb="name")
@ToMany            定义多个实体对应的关系
@ToOne              定义与另一个实体(一个实体对象)的关系
@Transient          添加该标记之后不会生成数据库表的列
@Unique              向数据库列添加一个唯一的约束
  五关于数据库的更新
   原理:首先创建临时表(数据格式和原表一模一样)。
             把当前表的数据插入到临时表中去。
             删除掉原表,创建新表。
             把临时表数据插入到新表中去,然后删除临时表。
  下边贴上国外大神的写的更新数据库的操作类
  
public class MigrationHelper2 {    public static boolean DEBUG = false;    private static String TAG = "MigrationHelper2";    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) {        printLog("【The Old Database Version】" + db.getVersion());        Database database = new StandardDatabase(db);        migrate(database, daoClasses);    }    public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {        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);        }    }}
    然后创建自定义的更新数据库类继承DaoMaster.OpenHelper
  
** * Created by wbxu on 2017/6/19. *  自定义  MySQLiteOpenHelper集成  DaoMaster.OpenHelper 重写更新数据库的方法 *   当app下的build.gradle  的schemaVersion数据库的版本号改变时,,创建数据库会调用onUpgrade更细数据库的方法 */public class MySQLiteOpenHelper extends DaoMaster.OpenHelper{    /**     *     * @param context  上下文     * @param name     原来定义的数据库的名字   新旧数据库一致     * @param factory  可以null     */    public MySQLiteOpenHelper(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) {        Log.d("flag","-----调用了");        //具体的数据转移在MigrationHelper2类中        /**         *  将db传入     将gen目录下的所有的Dao.类传入         */       MigrationHelper2.migrate(db,FruitDao.class, AnimalsDao.class, PeoreDao.class);    }}
     使用方法:
     1当新建一个表就是新建一个bean  然后build   makeProject 会在gen生成对应的dao文件   将类名传入MigrationHelper2.migrate(db,FruitDao.class, AnimalsDao.class, PeoreDao.class);这个更新的方法里
     2更改app下build.gradle的数据库的版本号
//初始化greendao基本信息
    greendao{
        schemaVersion 4
        daoPackage 'com.example.wbxu.mygreendaodemo.gen'
        targetGenDir 'src/main/java'
    }
     3调用让其更新
在想要更新的地方如mainActivity 或 Application   更新数据库
//传入参数二是新旧的数据库名字需要一致
  MySQLiteOpenHelper o=new MySQLiteOpenHelper(this,"MyGreenDb.db",null);
                DaoMaster daoMaster = new DaoMaster(o.getWritableDatabase());

源码下载:http://download.csdn.net/detail/bskfnvjtlyzmv867/9835023